1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.print;
18 
19 import android.content.pm.PackageManager;
20 import android.content.pm.PackageManager.NameNotFoundException;
21 import android.content.res.Resources.NotFoundException;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.text.TextUtils;
25 import android.util.ArrayMap;
26 import android.util.Log;
27 
28 import com.android.internal.R;
29 
30 import java.util.Map;
31 
32 /**
33  * This class represents the attributes of a print job. These attributes
34  * describe how the printed content should be laid out. For example, the
35  * print attributes may state that the content should be laid out on a
36  * letter size with 300 DPI (dots per inch) resolution, have a margin of
37  * 10 mills (thousand of an inch) on all sides, and be black and white.
38  */
39 public final class PrintAttributes implements Parcelable {
40     /** Color mode: Monochrome color scheme, for example one color is used. */
41     public static final int COLOR_MODE_MONOCHROME = 1 << 0;
42     /** Color mode: Color color scheme, for example many colors are used. */
43     public static final int COLOR_MODE_COLOR = 1 << 1;
44 
45     private static final int VALID_COLOR_MODES =
46             COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
47 
48     /** Duplex mode: No duplexing. */
49     public static final int DUPLEX_MODE_NONE = 1 << 0;
50     /** Duplex mode: Pages are turned sideways along the long edge - like a book. */
51     public static final int DUPLEX_MODE_LONG_EDGE = 1 << 1;
52     /** Duplex mode: Pages are turned upwards along the short edge - like a notpad. */
53     public static final int DUPLEX_MODE_SHORT_EDGE = 1 << 2;
54 
55     private static final int VALID_DUPLEX_MODES =
56             DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
57 
58     private MediaSize mMediaSize;
59     private Resolution mResolution;
60     private Margins mMinMargins;
61 
62     private int mColorMode;
63     private int mDuplexMode = DUPLEX_MODE_NONE;
64 
PrintAttributes()65     PrintAttributes() {
66         /* hide constructor */
67     }
68 
PrintAttributes(Parcel parcel)69     private PrintAttributes(Parcel parcel) {
70         mMediaSize = (parcel.readInt() ==  1) ? MediaSize.createFromParcel(parcel) : null;
71         mResolution = (parcel.readInt() ==  1) ? Resolution.createFromParcel(parcel) : null;
72         mMinMargins = (parcel.readInt() ==  1) ? Margins.createFromParcel(parcel) : null;
73         mColorMode = parcel.readInt();
74         mDuplexMode = parcel.readInt();
75     }
76 
77     /**
78      * Gets the media size.
79      *
80      * @return The media size or <code>null</code> if not set.
81      */
getMediaSize()82     public MediaSize getMediaSize() {
83         return mMediaSize;
84     }
85 
86     /**
87      * Sets the media size.
88      *
89      * @param mediaSize The media size.
90      *
91      * @hide
92      */
setMediaSize(MediaSize mediaSize)93     public void setMediaSize(MediaSize mediaSize) {
94         mMediaSize = mediaSize;
95     }
96 
97     /**
98      * Gets the resolution.
99      *
100      * @return The resolution or <code>null</code> if not set.
101      */
getResolution()102     public Resolution getResolution() {
103         return mResolution;
104     }
105 
106     /**
107      * Sets the resolution.
108      *
109      * @param resolution The resolution.
110      *
111      * @hide
112      */
setResolution(Resolution resolution)113     public void setResolution(Resolution resolution) {
114         mResolution = resolution;
115     }
116 
117     /**
118      * Gets the minimal margins. If the content does not fit
119      * these margins it will be clipped.
120      * <p>
121      * <strong>These margins are physically imposed by the printer and they
122      * are <em>not</em> rotated, i.e. they are the same for both portrait and
123      * landscape. For example, a printer may not be able to print in a stripe
124      * on both left and right sides of the page.
125      * </strong>
126      * </p>
127      *
128      * @return The margins or <code>null</code> if not set.
129      */
getMinMargins()130     public Margins getMinMargins() {
131         return mMinMargins;
132     }
133 
134     /**
135      * Sets the minimal margins. If the content does not fit
136      * these margins it will be clipped.
137      * <p>
138      * <strong>These margins are physically imposed by the printer and they
139      * are <em>not</em> rotated, i.e. they are the same for both portrait and
140      * landscape. For example, a printer may not be able to print in a stripe
141      * on both left and right sides of the page.
142      * </strong>
143      * </p>
144      *
145      * @param margins The margins.
146      *
147      * @hide
148      */
setMinMargins(Margins margins)149     public void setMinMargins(Margins margins) {
150         mMinMargins = margins;
151     }
152 
153     /**
154      * Gets the color mode.
155      *
156      * @return The color mode or zero if not set.
157      *
158      * @see #COLOR_MODE_COLOR
159      * @see #COLOR_MODE_MONOCHROME
160      */
getColorMode()161     public int getColorMode() {
162         return mColorMode;
163     }
164 
165     /**
166      * Sets the color mode.
167      *
168      * @param colorMode The color mode.
169      *
170      * @see #COLOR_MODE_MONOCHROME
171      * @see #COLOR_MODE_COLOR
172      *
173      * @hide
174      */
setColorMode(int colorMode)175     public void setColorMode(int colorMode) {
176         enforceValidColorMode(colorMode);
177         mColorMode = colorMode;
178     }
179 
180     /**
181      * Gets whether this print attributes are in portrait orientation,
182      * which is the media size is in portrait and all orientation dependent
183      * attributes such as resolution and margins are properly adjusted.
184      *
185      * @return Whether this print attributes are in portrait.
186      *
187      * @hide
188      */
isPortrait()189     public boolean isPortrait() {
190         return mMediaSize.isPortrait();
191     }
192 
193     /**
194      * Gets the duplex mode.
195      *
196      * @return The duplex mode.
197      *
198      * @see #DUPLEX_MODE_NONE
199      * @see #DUPLEX_MODE_LONG_EDGE
200      * @see #DUPLEX_MODE_SHORT_EDGE
201      */
getDuplexMode()202     public int getDuplexMode() {
203         return mDuplexMode;
204     }
205 
206     /**
207      * Sets the duplex mode.
208      *
209      * @param duplexMode The duplex mode.
210      *
211      * @see #DUPLEX_MODE_NONE
212      * @see #DUPLEX_MODE_LONG_EDGE
213      * @see #DUPLEX_MODE_SHORT_EDGE
214      *
215      * @hide
216      */
setDuplexMode(int duplexMode)217     public void setDuplexMode(int duplexMode) {
218         enforceValidDuplexMode(duplexMode);
219         mDuplexMode = duplexMode;
220     }
221 
222     /**
223      * Gets a new print attributes instance which is in portrait orientation,
224      * which is the media size is in portrait and all orientation dependent
225      * attributes such as resolution and margins are properly adjusted.
226      *
227      * @return New instance in portrait orientation if this one is in
228      * landscape, otherwise this instance.
229      *
230      * @hide
231      */
asPortrait()232     public PrintAttributes asPortrait() {
233         if (isPortrait()) {
234             return this;
235         }
236 
237         PrintAttributes attributes = new PrintAttributes();
238 
239         // Rotate the media size.
240         attributes.setMediaSize(getMediaSize().asPortrait());
241 
242         // Rotate the resolution.
243         Resolution oldResolution = getResolution();
244         Resolution newResolution = new Resolution(
245                 oldResolution.getId(),
246                 oldResolution.getLabel(),
247                 oldResolution.getVerticalDpi(),
248                 oldResolution.getHorizontalDpi());
249         attributes.setResolution(newResolution);
250 
251         // Do not rotate the physical margins.
252         attributes.setMinMargins(getMinMargins());
253 
254         attributes.setColorMode(getColorMode());
255         attributes.setDuplexMode(getDuplexMode());
256 
257         return attributes;
258     }
259 
260     /**
261      * Gets a new print attributes instance which is in landscape orientation,
262      * which is the media size is in landscape and all orientation dependent
263      * attributes such as resolution and margins are properly adjusted.
264      *
265      * @return New instance in landscape orientation if this one is in
266      * portrait, otherwise this instance.
267      *
268      * @hide
269      */
asLandscape()270     public PrintAttributes asLandscape() {
271         if (!isPortrait()) {
272             return this;
273         }
274 
275         PrintAttributes attributes = new PrintAttributes();
276 
277         // Rotate the media size.
278         attributes.setMediaSize(getMediaSize().asLandscape());
279 
280         // Rotate the resolution.
281         Resolution oldResolution = getResolution();
282         Resolution newResolution = new Resolution(
283                 oldResolution.getId(),
284                 oldResolution.getLabel(),
285                 oldResolution.getVerticalDpi(),
286                 oldResolution.getHorizontalDpi());
287         attributes.setResolution(newResolution);
288 
289         // Do not rotate the physical margins.
290         attributes.setMinMargins(getMinMargins());
291 
292         attributes.setColorMode(getColorMode());
293         attributes.setDuplexMode(getDuplexMode());
294 
295         return attributes;
296     }
297 
298     @Override
writeToParcel(Parcel parcel, int flags)299     public void writeToParcel(Parcel parcel, int flags) {
300         if (mMediaSize != null) {
301             parcel.writeInt(1);
302             mMediaSize.writeToParcel(parcel);
303         } else {
304             parcel.writeInt(0);
305         }
306         if (mResolution != null) {
307             parcel.writeInt(1);
308             mResolution.writeToParcel(parcel);
309         } else {
310             parcel.writeInt(0);
311         }
312         if (mMinMargins != null) {
313             parcel.writeInt(1);
314             mMinMargins.writeToParcel(parcel);
315         } else {
316             parcel.writeInt(0);
317         }
318         parcel.writeInt(mColorMode);
319         parcel.writeInt(mDuplexMode);
320     }
321 
322     @Override
describeContents()323     public int describeContents() {
324         return 0;
325     }
326 
327     @Override
hashCode()328     public int hashCode() {
329         final int prime = 31;
330         int result = 1;
331         result = prime * result + mColorMode;
332         result = prime * result + mDuplexMode;
333         result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
334         result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
335         result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
336         return result;
337     }
338 
339     @Override
equals(Object obj)340     public boolean equals(Object obj) {
341         if (this == obj) {
342             return true;
343         }
344         if (obj == null) {
345             return false;
346         }
347         if (getClass() != obj.getClass()) {
348             return false;
349         }
350         PrintAttributes other = (PrintAttributes) obj;
351         if (mColorMode != other.mColorMode) {
352             return false;
353         }
354         if (mDuplexMode != other.mDuplexMode) {
355             return false;
356         }
357         if (mMinMargins == null) {
358             if (other.mMinMargins != null) {
359                 return false;
360             }
361         } else if (!mMinMargins.equals(other.mMinMargins)) {
362             return false;
363         }
364         if (mMediaSize == null) {
365             if (other.mMediaSize != null) {
366                 return false;
367             }
368         } else if (!mMediaSize.equals(other.mMediaSize)) {
369             return false;
370         }
371         if (mResolution == null) {
372             if (other.mResolution != null) {
373                 return false;
374             }
375         } else if (!mResolution.equals(other.mResolution)) {
376             return false;
377         }
378         return true;
379     }
380 
381     @Override
toString()382     public String toString() {
383         StringBuilder builder = new StringBuilder();
384         builder.append("PrintAttributes{");
385         builder.append("mediaSize: ").append(mMediaSize);
386         if (mMediaSize != null) {
387             builder.append(", orientation: ").append(mMediaSize.isPortrait()
388                     ? "portrait" : "landscape");
389         } else {
390             builder.append(", orientation: ").append("null");
391         }
392         builder.append(", resolution: ").append(mResolution);
393         builder.append(", minMargins: ").append(mMinMargins);
394         builder.append(", colorMode: ").append(colorModeToString(mColorMode));
395         builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode));
396         builder.append("}");
397         return builder.toString();
398     }
399 
400     /** @hide */
clear()401     public void clear() {
402         mMediaSize = null;
403         mResolution = null;
404         mMinMargins = null;
405         mColorMode = 0;
406         mDuplexMode = DUPLEX_MODE_NONE;
407     }
408 
409     /**
410      * @hide
411      */
copyFrom(PrintAttributes other)412     public void copyFrom(PrintAttributes other) {
413         mMediaSize = other.mMediaSize;
414         mResolution = other.mResolution;
415         mMinMargins = other.mMinMargins;
416         mColorMode = other.mColorMode;
417         mDuplexMode = other.mDuplexMode;
418     }
419 
420     /**
421      * This class specifies a supported media size. Media size is the
422      * dimension of the media on which the content is printed. For
423      * example, the {@link #NA_LETTER} media size designates a page
424      * with size 8.5" x 11".
425      */
426     public static final class MediaSize {
427         private static final String LOG_TAG = "MediaSize";
428 
429         private static final Map<String, MediaSize> sIdToMediaSizeMap =
430                 new ArrayMap<String, MediaSize>();
431 
432         /**
433          * Unknown media size in portrait mode.
434          * <p>
435          * <strong>Note: </strong>This is for specifying orientation without media
436          * size. You should not use the dimensions reported by this instance.
437          * </p>
438          */
439         public static final MediaSize UNKNOWN_PORTRAIT =
440                 new MediaSize("UNKNOWN_PORTRAIT", "android",
441                         R.string.mediasize_unknown_portrait, 1, Integer.MAX_VALUE);
442 
443         /**
444          * Unknown media size in landscape mode.
445          * <p>
446          * <strong>Note: </strong>This is for specifying orientation without media
447          * size. You should not use the dimensions reported by this instance.
448          * </p>
449          */
450         public static final MediaSize UNKNOWN_LANDSCAPE =
451                 new MediaSize("UNKNOWN_LANDSCAPE", "android",
452                         R.string.mediasize_unknown_landscape, Integer.MAX_VALUE, 1);
453 
454         // ISO sizes
455 
456         /** ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") */
457         public static final MediaSize ISO_A0 =
458                 new MediaSize("ISO_A0", "android", R.string.mediasize_iso_a0, 33110, 46810);
459         /** ISO A1 media size: 594mm x 841mm (23.39" x 33.11") */
460         public static final MediaSize ISO_A1 =
461                 new MediaSize("ISO_A1", "android", R.string.mediasize_iso_a1, 23390, 33110);
462         /** ISO A2 media size: 420mm x 594mm (16.54" x 23.39") */
463         public static final MediaSize ISO_A2 =
464                 new MediaSize("ISO_A2", "android", R.string.mediasize_iso_a2, 16540, 23390);
465         /** ISO A3 media size: 297mm x 420mm (11.69" x 16.54") */
466         public static final MediaSize ISO_A3 =
467                 new MediaSize("ISO_A3", "android", R.string.mediasize_iso_a3, 11690, 16540);
468         /** ISO A4 media size: 210mm x 297mm (8.27" x 11.69") */
469         public static final MediaSize ISO_A4 =
470                 new MediaSize("ISO_A4", "android", R.string.mediasize_iso_a4, 8270, 11690);
471         /** ISO A5 media size: 148mm x 210mm (5.83" x 8.27") */
472         public static final MediaSize ISO_A5 =
473                 new MediaSize("ISO_A5", "android", R.string.mediasize_iso_a5, 5830, 8270);
474         /** ISO A6 media size: 105mm x 148mm (4.13" x 5.83") */
475         public static final MediaSize ISO_A6 =
476                 new MediaSize("ISO_A6", "android", R.string.mediasize_iso_a6, 4130, 5830);
477         /** ISO A7 media size: 74mm x 105mm (2.91" x 4.13") */
478         public static final MediaSize ISO_A7 =
479                 new MediaSize("ISO_A7", "android", R.string.mediasize_iso_a7, 2910, 4130);
480         /** ISO A8 media size: 52mm x 74mm (2.05" x 2.91") */
481         public static final MediaSize ISO_A8 =
482                 new MediaSize("ISO_A8", "android", R.string.mediasize_iso_a8, 2050, 2910);
483         /** ISO A9 media size: 37mm x 52mm (1.46" x 2.05") */
484         public static final MediaSize ISO_A9 =
485                 new MediaSize("ISO_A9", "android", R.string.mediasize_iso_a9, 1460, 2050);
486         /** ISO A10 media size: 26mm x 37mm (1.02" x 1.46") */
487         public static final MediaSize ISO_A10 =
488                 new MediaSize("ISO_A10", "android", R.string.mediasize_iso_a10, 1020, 1460);
489 
490         /** ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") */
491         public static final MediaSize ISO_B0 =
492                 new MediaSize("ISO_B0", "android", R.string.mediasize_iso_b0, 39370, 55670);
493         /** ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") */
494         public static final MediaSize ISO_B1 =
495                 new MediaSize("ISO_B1", "android", R.string.mediasize_iso_b1, 27830, 39370);
496         /** ISO B2 media size: 500mm x 707mm (19.69" x 27.83") */
497         public static final MediaSize ISO_B2 =
498                 new MediaSize("ISO_B2", "android", R.string.mediasize_iso_b2, 19690, 27830);
499         /** ISO B3 media size: 353mm x 500mm (13.90" x 19.69") */
500         public static final MediaSize ISO_B3 =
501                 new MediaSize("ISO_B3", "android", R.string.mediasize_iso_b3, 13900, 19690);
502         /** ISO B4 media size: 250mm x 353mm (9.84" x 13.90") */
503         public static final MediaSize ISO_B4 =
504                 new MediaSize("ISO_B4", "android", R.string.mediasize_iso_b4, 9840, 13900);
505         /** ISO B5 media size: 176mm x 250mm (6.93" x 9.84") */
506         public static final MediaSize ISO_B5 =
507                 new MediaSize("ISO_B5", "android", R.string.mediasize_iso_b5, 6930, 9840);
508         /** ISO B6 media size: 125mm x 176mm (4.92" x 6.93") */
509         public static final MediaSize ISO_B6 =
510                 new MediaSize("ISO_B6", "android", R.string.mediasize_iso_b6, 4920, 6930);
511         /** ISO B7 media size: 88mm x 125mm (3.46" x 4.92") */
512         public static final MediaSize ISO_B7 =
513                 new MediaSize("ISO_B7", "android", R.string.mediasize_iso_b7, 3460, 4920);
514         /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") */
515         public static final MediaSize ISO_B8 =
516                 new MediaSize("ISO_B8", "android", R.string.mediasize_iso_b8, 2440, 3460);
517         /** ISO B9 media size: 44mm x 62mm (1.73" x 2.44") */
518         public static final MediaSize ISO_B9 =
519                 new MediaSize("ISO_B9", "android", R.string.mediasize_iso_b9, 1730, 2440);
520         /** ISO B10 media size: 31mm x 44mm (1.22" x 1.73") */
521         public static final MediaSize ISO_B10 =
522                 new MediaSize("ISO_B10", "android", R.string.mediasize_iso_b10, 1220, 1730);
523 
524         /** ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") */
525         public static final MediaSize ISO_C0 =
526                 new MediaSize("ISO_C0", "android", R.string.mediasize_iso_c0, 36100, 51060);
527         /** ISO C1 media size: 648mm x 917mm (25.51" x 36.10") */
528         public static final MediaSize ISO_C1 =
529                 new MediaSize("ISO_C1", "android", R.string.mediasize_iso_c1, 25510, 36100);
530         /** ISO C2 media size: 458mm x 648mm (18.03" x 25.51") */
531         public static final MediaSize ISO_C2 =
532                 new MediaSize("ISO_C2", "android", R.string.mediasize_iso_c2, 18030, 25510);
533         /** ISO C3 media size: 324mm x 458mm (12.76" x 18.03") */
534         public static final MediaSize ISO_C3 =
535                 new MediaSize("ISO_C3", "android", R.string.mediasize_iso_c3, 12760, 18030);
536         /** ISO C4 media size: 229mm x 324mm (9.02" x 12.76") */
537         public static final MediaSize ISO_C4 =
538                 new MediaSize("ISO_C4", "android", R.string.mediasize_iso_c4, 9020, 12760);
539         /** ISO C5 media size: 162mm x 229mm (6.38" x 9.02") */
540         public static final MediaSize ISO_C5 =
541                 new MediaSize("ISO_C5", "android", R.string.mediasize_iso_c5, 6380, 9020);
542         /** ISO C6 media size: 114mm x 162mm (4.49" x 6.38") */
543         public static final MediaSize ISO_C6 =
544                 new MediaSize("ISO_C6", "android", R.string.mediasize_iso_c6, 4490, 6380);
545         /** ISO C7 media size: 81mm x 114mm (3.19" x 4.49") */
546         public static final MediaSize ISO_C7 =
547                 new MediaSize("ISO_C7", "android", R.string.mediasize_iso_c7, 3190, 4490);
548         /** ISO C8 media size: 57mm x 81mm (2.24" x 3.19") */
549         public static final MediaSize ISO_C8 =
550                 new MediaSize("ISO_C8", "android", R.string.mediasize_iso_c8, 2240, 3190);
551         /** ISO C9 media size: 40mm x 57mm (1.57" x 2.24") */
552         public static final MediaSize ISO_C9 =
553                 new MediaSize("ISO_C9", "android", R.string.mediasize_iso_c9, 1570, 2240);
554         /** ISO C10 media size: 28mm x 40mm (1.10" x 1.57") */
555         public static final MediaSize ISO_C10 =
556                 new MediaSize("ISO_C10", "android", R.string.mediasize_iso_c10, 1100, 1570);
557 
558         // North America
559 
560         /** North America Letter media size: 8.5" x 11" (279mm x 216mm) */
561         public static final MediaSize NA_LETTER =
562                 new MediaSize("NA_LETTER", "android", R.string.mediasize_na_letter, 8500, 11000);
563         /** North America Government-Letter media size: 8.0" x 10.5" (203mm x 267mm) */
564         public static final MediaSize NA_GOVT_LETTER =
565                 new MediaSize("NA_GOVT_LETTER", "android",
566                         R.string.mediasize_na_gvrnmt_letter, 8000, 10500);
567         /** North America Legal media size: 8.5" x 14" (216mm x 356mm) */
568         public static final MediaSize NA_LEGAL =
569                 new MediaSize("NA_LEGAL", "android", R.string.mediasize_na_legal, 8500, 14000);
570         /** North America Junior Legal media size: 8.0" x 5.0" (203mm × 127mm) */
571         public static final MediaSize NA_JUNIOR_LEGAL =
572                 new MediaSize("NA_JUNIOR_LEGAL", "android",
573                         R.string.mediasize_na_junior_legal, 8000, 5000);
574         /** North America Ledger media size: 17" x 11" (432mm × 279mm) */
575         public static final MediaSize NA_LEDGER =
576                 new MediaSize("NA_LEDGER", "android", R.string.mediasize_na_ledger, 17000, 11000);
577         /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
578         public static final MediaSize NA_TABLOID =
579                 new MediaSize("NA_TABLOID", "android",
580                         R.string.mediasize_na_tabloid, 11000, 17000);
581         /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
582         public static final MediaSize NA_INDEX_3X5 =
583                 new MediaSize("NA_INDEX_3X5", "android",
584                         R.string.mediasize_na_index_3x5, 3000, 5000);
585         /** North America Index Card 4x6 media size: 4" x 6" (102mm x 152mm) */
586         public static final MediaSize NA_INDEX_4X6 =
587                 new MediaSize("NA_INDEX_4X6", "android",
588                         R.string.mediasize_na_index_4x6, 4000, 6000);
589         /** North America Index Card 5x8 media size: 5" x 8" (127mm x 203mm) */
590         public static final MediaSize NA_INDEX_5X8 =
591                 new MediaSize("NA_INDEX_5X8", "android",
592                         R.string.mediasize_na_index_5x8, 5000, 8000);
593         /** North America Monarch media size: 7.25" x 10.5" (184mm x 267mm) */
594         public static final MediaSize NA_MONARCH =
595                 new MediaSize("NA_MONARCH", "android",
596                         R.string.mediasize_na_monarch, 7250, 10500);
597         /** North America Quarto media size: 8" x 10" (203mm x 254mm) */
598         public static final MediaSize NA_QUARTO =
599                 new MediaSize("NA_QUARTO", "android",
600                         R.string.mediasize_na_quarto, 8000, 10000);
601         /** North America Foolscap media size: 8" x 13" (203mm x 330mm) */
602         public static final MediaSize NA_FOOLSCAP =
603                 new MediaSize("NA_FOOLSCAP", "android",
604                         R.string.mediasize_na_foolscap, 8000, 13000);
605 
606         // Chinese
607 
608         /** Chinese ROC 8K media size: 270mm x 390mm (10.629" x 15.3543") */
609         public static final MediaSize ROC_8K =
610                 new MediaSize("ROC_8K", "android",
611                         R.string.mediasize_chinese_roc_8k, 10629, 15354);
612         /** Chinese ROC 16K media size: 195mm x 270mm (7.677" x 10.629") */
613         public static final MediaSize ROC_16K =
614                 new MediaSize("ROC_16K", "android",
615                         R.string.mediasize_chinese_roc_16k, 7677, 10629);
616 
617         /** Chinese PRC 1 media size: 102mm x 165mm (4.015" x 6.496") */
618         public static final MediaSize PRC_1 =
619                 new MediaSize("PRC_1", "android",
620                         R.string.mediasize_chinese_prc_1, 4015, 6496);
621         /** Chinese PRC 2 media size: 102mm x 176mm (4.015" x 6.929") */
622         public static final MediaSize PRC_2 =
623                 new MediaSize("PRC_2", "android",
624                         R.string.mediasize_chinese_prc_2, 4015, 6929);
625         /** Chinese PRC 3 media size: 125mm x 176mm (4.921" x 6.929") */
626         public static final MediaSize PRC_3 =
627                 new MediaSize("PRC_3", "android",
628                         R.string.mediasize_chinese_prc_3, 4921, 6929);
629         /** Chinese PRC 4 media size: 110mm x 208mm (4.330" x 8.189") */
630         public static final MediaSize PRC_4 =
631                 new MediaSize("PRC_4", "android",
632                         R.string.mediasize_chinese_prc_4, 4330, 8189);
633         /** Chinese PRC 5 media size: 110mm x 220mm (4.330" x 8.661") */
634         public static final MediaSize PRC_5 =
635                 new MediaSize("PRC_5", "android",
636                         R.string.mediasize_chinese_prc_5, 4330, 8661);
637         /** Chinese PRC 6 media size: 120mm x 320mm (4.724" x 12.599") */
638         public static final MediaSize PRC_6 =
639                 new MediaSize("PRC_6", "android",
640                         R.string.mediasize_chinese_prc_6, 4724, 12599);
641         /** Chinese PRC 7 media size: 160mm x 230mm (6.299" x 9.055") */
642         public static final MediaSize PRC_7 =
643                 new MediaSize("PRC_7", "android",
644                         R.string.mediasize_chinese_prc_7, 6299, 9055);
645         /** Chinese PRC 8 media size: 120mm x 309mm (4.724" x 12.165") */
646         public static final MediaSize PRC_8 =
647                 new MediaSize("PRC_8", "android",
648                         R.string.mediasize_chinese_prc_8, 4724, 12165);
649         /** Chinese PRC 9 media size: 229mm x 324mm (9.016" x 12.756") */
650         public static final MediaSize PRC_9 =
651                 new MediaSize("PRC_9", "android",
652                         R.string.mediasize_chinese_prc_9, 9016, 12756);
653         /** Chinese PRC 10 media size: 324mm x 458mm (12.756" x 18.032") */
654         public static final MediaSize PRC_10 =
655                 new MediaSize("PRC_10", "android",
656                         R.string.mediasize_chinese_prc_10, 12756, 18032);
657 
658         /** Chinese PRC 16k media size: 146mm x 215mm (5.749" x 8.465") */
659         public static final MediaSize PRC_16K =
660                 new MediaSize("PRC_16K", "android",
661                         R.string.mediasize_chinese_prc_16k, 5749, 8465);
662         /** Chinese Pa Kai media size: 267mm x 389mm (10.512" x 15.315") */
663         public static final MediaSize OM_PA_KAI =
664                 new MediaSize("OM_PA_KAI", "android",
665                         R.string.mediasize_chinese_om_pa_kai, 10512, 15315);
666         /** Chinese Dai Pa Kai media size: 275mm x 395mm (10.827" x 15.551") */
667         public static final MediaSize OM_DAI_PA_KAI =
668                 new MediaSize("OM_DAI_PA_KAI", "android",
669                         R.string.mediasize_chinese_om_dai_pa_kai, 10827, 15551);
670         /** Chinese Jurro Ku Kai media size: 198mm x 275mm (7.796" x 10.827") */
671         public static final MediaSize OM_JUURO_KU_KAI =
672                 new MediaSize("OM_JUURO_KU_KAI", "android",
673                         R.string.mediasize_chinese_om_jurro_ku_kai, 7796, 10827);
674 
675         // Japanese
676 
677         /** Japanese JIS B10 media size: 32mm x 45mm (1.259" x 1.772") */
678         public static final MediaSize JIS_B10 =
679                 new MediaSize("JIS_B10", "android",
680                         R.string.mediasize_japanese_jis_b10, 1259, 1772);
681         /** Japanese JIS B9 media size: 45mm x 64mm (1.772" x 2.52") */
682         public static final MediaSize JIS_B9 =
683                 new MediaSize("JIS_B9", "android",
684                         R.string.mediasize_japanese_jis_b9, 1772, 2520);
685         /** Japanese JIS B8 media size: 64mm x 91mm (2.52" x 3.583") */
686         public static final MediaSize JIS_B8 =
687                 new MediaSize("JIS_B8", "android",
688                         R.string.mediasize_japanese_jis_b8, 2520, 3583);
689         /** Japanese JIS B7 media size: 91mm x 128mm (3.583" x 5.049") */
690         public static final MediaSize JIS_B7 =
691                 new MediaSize("JIS_B7", "android",
692                         R.string.mediasize_japanese_jis_b7, 3583, 5049);
693         /** Japanese JIS B6 media size: 128mm x 182mm (5.049" x 7.165") */
694         public static final MediaSize JIS_B6 =
695                 new MediaSize("JIS_B6", "android",
696                         R.string.mediasize_japanese_jis_b6, 5049, 7165);
697         /** Japanese JIS B5 media size: 182mm x 257mm (7.165" x 10.118") */
698         public static final MediaSize JIS_B5 =
699                 new MediaSize("JIS_B5", "android",
700                         R.string.mediasize_japanese_jis_b5, 7165, 10118);
701         /** Japanese JIS B4 media size: 257mm x 364mm (10.118" x 14.331") */
702         public static final MediaSize JIS_B4 =
703                 new MediaSize("JIS_B4", "android",
704                         R.string.mediasize_japanese_jis_b4, 10118, 14331);
705         /** Japanese JIS B3 media size: 364mm x 515mm (14.331" x 20.276") */
706         public static final MediaSize JIS_B3 =
707                 new MediaSize("JIS_B3", "android",
708                         R.string.mediasize_japanese_jis_b3, 14331, 20276);
709         /** Japanese JIS B2 media size: 515mm x 728mm (20.276" x 28.661") */
710         public static final MediaSize JIS_B2 =
711                 new MediaSize("JIS_B2", "android",
712                         R.string.mediasize_japanese_jis_b2, 20276, 28661);
713         /** Japanese JIS B1 media size: 728mm x 1030mm (28.661" x 40.551") */
714         public static final MediaSize JIS_B1 =
715                 new MediaSize("JIS_B1", "android",
716                         R.string.mediasize_japanese_jis_b1, 28661, 40551);
717         /** Japanese JIS B0 media size: 1030mm x 1456mm (40.551" x 57.323") */
718         public static final MediaSize JIS_B0 =
719                 new MediaSize("JIS_B0", "android",
720                         R.string.mediasize_japanese_jis_b0, 40551, 57323);
721 
722         /** Japanese JIS Exec media size: 216mm x 330mm (8.504" x 12.992") */
723         public static final MediaSize JIS_EXEC =
724                 new MediaSize("JIS_EXEC", "android",
725                         R.string.mediasize_japanese_jis_exec, 8504, 12992);
726 
727         /** Japanese Chou4 media size: 90mm x 205mm (3.543" x 8.071") */
728         public static final MediaSize JPN_CHOU4 =
729                 new MediaSize("JPN_CHOU4", "android",
730                         R.string.mediasize_japanese_chou4, 3543, 8071);
731         /** Japanese Chou3 media size: 120mm x 235mm (4.724" x 9.252") */
732         public static final MediaSize JPN_CHOU3 =
733                 new MediaSize("JPN_CHOU3", "android",
734                         R.string.mediasize_japanese_chou3, 4724, 9252);
735         /** Japanese Chou2 media size: 111.1mm x 146mm (4.374" x 5.748") */
736         public static final MediaSize JPN_CHOU2 =
737                 new MediaSize("JPN_CHOU2", "android",
738                         R.string.mediasize_japanese_chou2, 4374, 5748);
739 
740         /** Japanese Hagaki media size: 100mm x 148mm (3.937" x 5.827") */
741         public static final MediaSize JPN_HAGAKI =
742                 new MediaSize("JPN_HAGAKI", "android",
743                         R.string.mediasize_japanese_hagaki, 3937, 5827);
744         /** Japanese Oufuku media size: 148mm x 200mm (5.827" x 7.874") */
745         public static final MediaSize JPN_OUFUKU =
746                 new MediaSize("JPN_OUFUKU", "android",
747                         R.string.mediasize_japanese_oufuku, 5827, 7874);
748 
749         /** Japanese Kahu media size: 240mm x 322.1mm (9.449" x 12.681") */
750         public static final MediaSize JPN_KAHU =
751                 new MediaSize("JPN_KAHU", "android",
752                         R.string.mediasize_japanese_kahu, 9449, 12681);
753         /** Japanese Kaku2 media size: 240mm x 332mm (9.449" x 13.071") */
754         public static final MediaSize JPN_KAKU2 =
755                 new MediaSize("JPN_KAKU2", "android",
756                         R.string.mediasize_japanese_kaku2, 9449, 13071);
757 
758         /** Japanese You4 media size: 105mm x 235mm (4.134" x 9.252") */
759         public static final MediaSize JPN_YOU4 =
760                 new MediaSize("JPN_YOU4", "android",
761                         R.string.mediasize_japanese_you4, 4134, 9252);
762 
763         private final String mId;
764         /**@hide */
765         public final String mLabel;
766         /**@hide */
767         public final String mPackageName;
768         /**@hide */
769         public final int mLabelResId;
770         private final int mWidthMils;
771         private final int mHeightMils;
772 
773         /**
774          * Creates a new instance.
775          *
776          * @param id The unique media size id.
777          * @param packageName The name of the creating package.
778          * @param labelResId The resource if of a human readable label.
779          * @param widthMils The width in mils (thousands of an inch).
780          * @param heightMils The height in mils (thousands of an inch).
781          *
782          * @throws IllegalArgumentException If the id is empty or the label
783          * is empty or the widthMils is less than or equal to zero or the
784          * heightMils is less than or equal to zero.
785          *
786          * @hide
787          */
MediaSize(String id, String packageName, int labelResId, int widthMils, int heightMils)788         public MediaSize(String id, String packageName, int labelResId,
789                 int widthMils, int heightMils) {
790             if (TextUtils.isEmpty(id)) {
791                 throw new IllegalArgumentException("id cannot be empty.");
792             }
793             if (TextUtils.isEmpty(packageName)) {
794                 throw new IllegalArgumentException("packageName cannot be empty.");
795             }
796             if (labelResId <= 0) {
797                 throw new IllegalArgumentException("labelResId must be greater than zero.");
798             }
799             if (widthMils <= 0) {
800                 throw new IllegalArgumentException("widthMils "
801                         + "cannot be less than or equal to zero.");
802             }
803             if (heightMils <= 0) {
804                 throw new IllegalArgumentException("heightMils "
805                        + "cannot be less than or euqual to zero.");
806             }
807             mPackageName = packageName;
808             mId = id;
809             mLabelResId = labelResId;
810             mWidthMils = widthMils;
811             mHeightMils = heightMils;
812             mLabel = null;
813 
814             // Build this mapping only for predefined media sizes.
815             sIdToMediaSizeMap.put(mId, this);
816         }
817 
818         /**
819          * Creates a new instance.
820          *
821          * @param id The unique media size id. It is unique amongst other media sizes
822          *        supported by the printer.
823          * @param label The <strong>localized</strong> human readable label.
824          * @param widthMils The width in mils (thousands of an inch).
825          * @param heightMils The height in mils (thousands of an inch).
826          *
827          * @throws IllegalArgumentException If the id is empty or the label is empty
828          * or the widthMils is less than or equal to zero or the heightMils is less
829          * than or equal to zero.
830          */
MediaSize(String id, String label, int widthMils, int heightMils)831         public MediaSize(String id, String label, int widthMils, int heightMils) {
832             if (TextUtils.isEmpty(id)) {
833                 throw new IllegalArgumentException("id cannot be empty.");
834             }
835             if (TextUtils.isEmpty(label)) {
836                 throw new IllegalArgumentException("label cannot be empty.");
837             }
838             if (widthMils <= 0) {
839                 throw new IllegalArgumentException("widthMils "
840                         + "cannot be less than or equal to zero.");
841             }
842             if (heightMils <= 0) {
843                 throw new IllegalArgumentException("heightMils "
844                        + "cannot be less than or euqual to zero.");
845             }
846             mId = id;
847             mLabel = label;
848             mWidthMils = widthMils;
849             mHeightMils = heightMils;
850             mLabelResId = 0;
851             mPackageName = null;
852         }
853 
854         /** @hide */
MediaSize(String id, String label, String packageName, int widthMils, int heightMils, int labelResId)855         public MediaSize(String id, String label, String packageName,
856                 int widthMils, int heightMils, int labelResId) {
857             mPackageName = packageName;
858             mId = id;
859             mLabelResId = labelResId;
860             mWidthMils = widthMils;
861             mHeightMils = heightMils;
862             mLabel = label;
863         }
864 
865         /**
866          * Gets the unique media size id. It is unique amongst other media sizes
867          * supported by the printer.
868          * <p>
869          * This id is defined by the client that generated the media size
870          * instance and should not be interpreted by other parties.
871          * </p>
872          *
873          * @return The unique media size id.
874          */
getId()875         public String getId() {
876             return mId;
877         }
878 
879         /**
880          * Gets the human readable media size label.
881          *
882          * @param packageManager The package manager for loading the label.
883          * @return The human readable label.
884          */
getLabel(PackageManager packageManager)885         public String getLabel(PackageManager packageManager) {
886             if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
887                 try {
888                     return packageManager.getResourcesForApplication(
889                             mPackageName).getString(mLabelResId);
890                 } catch (NotFoundException nfe) {
891                     Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
892                             + " from package " + mPackageName);
893                 } catch (NameNotFoundException nnfee) {
894                     Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
895                             + " from package " + mPackageName);
896                 }
897             }
898             return mLabel;
899         }
900 
901         /**
902          * Gets the media width in mils (thousands of an inch).
903          *
904          * @return The media width.
905          */
getWidthMils()906         public int getWidthMils() {
907             return mWidthMils;
908         }
909 
910         /**
911          * Gets the media height in mils (thousands of an inch).
912          *
913          * @return The media height.
914          */
getHeightMils()915         public int getHeightMils() {
916             return mHeightMils;
917         }
918 
919         /**
920          * Gets whether this media size is in portrait which is the
921          * height is greater or equal to the width.
922          *
923          * @return True if the media size is in portrait, false if
924          * it is in landscape.
925          */
isPortrait()926         public boolean isPortrait() {
927             return mHeightMils >= mWidthMils;
928         }
929 
930         /**
931          * Returns a new media size instance in a portrait orientation,
932          * which is the height is the greater dimension.
933          *
934          * @return New instance in landscape orientation if this one
935          * is in landscape, otherwise this instance.
936          */
asPortrait()937         public MediaSize asPortrait() {
938             if (isPortrait()) {
939                 return this;
940             }
941             return new MediaSize(mId, mLabel, mPackageName,
942                     Math.min(mWidthMils, mHeightMils),
943                     Math.max(mWidthMils, mHeightMils),
944                     mLabelResId);
945         }
946 
947         /**
948          * Returns a new media size instance in a landscape orientation,
949          * which is the height is the lesser dimension.
950          *
951          * @return New instance in landscape orientation if this one
952          * is in portrait, otherwise this instance.
953          */
asLandscape()954         public MediaSize asLandscape() {
955             if (!isPortrait()) {
956                 return this;
957             }
958             return new MediaSize(mId, mLabel, mPackageName,
959                     Math.max(mWidthMils, mHeightMils),
960                     Math.min(mWidthMils, mHeightMils),
961                     mLabelResId);
962         }
963 
writeToParcel(Parcel parcel)964         void writeToParcel(Parcel parcel) {
965             parcel.writeString(mId);
966             parcel.writeString(mLabel);
967             parcel.writeString(mPackageName);
968             parcel.writeInt(mWidthMils);
969             parcel.writeInt(mHeightMils);
970             parcel.writeInt(mLabelResId);
971         }
972 
createFromParcel(Parcel parcel)973         static MediaSize createFromParcel(Parcel parcel) {
974             return new MediaSize(
975                     parcel.readString(),
976                     parcel.readString(),
977                     parcel.readString(),
978                     parcel.readInt(),
979                     parcel.readInt(),
980                     parcel.readInt());
981         }
982 
983         @Override
hashCode()984         public int hashCode() {
985             final int prime = 31;
986             int result = 1;
987             result = prime * result + mWidthMils;
988             result = prime * result + mHeightMils;
989             return result;
990         }
991 
992         @Override
equals(Object obj)993         public boolean equals(Object obj) {
994             if (this == obj) {
995                 return true;
996             }
997             if (obj == null) {
998                 return false;
999             }
1000             if (getClass() != obj.getClass()) {
1001                 return false;
1002             }
1003             MediaSize other = (MediaSize) obj;
1004             if (mWidthMils != other.mWidthMils) {
1005                 return false;
1006             }
1007             if (mHeightMils != other.mHeightMils) {
1008                 return false;
1009             }
1010             return true;
1011         }
1012 
1013         @Override
toString()1014         public String toString() {
1015             StringBuilder builder = new StringBuilder();
1016             builder.append("MediaSize{");
1017             builder.append("id: ").append(mId);
1018             builder.append(", label: ").append(mLabel);
1019             builder.append(", packageName: ").append(mPackageName);
1020             builder.append(", heightMils: ").append(mHeightMils);
1021             builder.append(", widthMils: ").append(mWidthMils);
1022             builder.append(", labelResId: ").append(mLabelResId);
1023             builder.append("}");
1024             return builder.toString();
1025         }
1026 
1027         /**
1028          * Gets a standard media size given its id.
1029          *
1030          * @param id The media size id.
1031          * @return The media size for the given id or null.
1032          *
1033          * @hide
1034          */
getStandardMediaSizeById(String id)1035         public static MediaSize getStandardMediaSizeById(String id) {
1036             return sIdToMediaSizeMap.get(id);
1037         }
1038     }
1039 
1040     /**
1041      * This class specifies a supported resolution in DPI (dots per inch).
1042      * Resolution defines how many points with different color can be placed
1043      * on one inch in horizontal or vertical direction of the target media.
1044      * For example, a printer with 600 DPI can produce higher quality images
1045      * the one with 300 DPI resolution.
1046      */
1047     public static final class Resolution {
1048         private final String mId;
1049         private final String mLabel;
1050         private final int mHorizontalDpi;
1051         private final int mVerticalDpi;
1052 
1053         /**
1054          * Creates a new instance.
1055          *
1056          * @param id The unique resolution id. It is unique amongst other resolutions
1057          *        supported by the printer.
1058          * @param label The <strong>localized</strong> human readable label.
1059          * @param horizontalDpi The horizontal resolution in DPI (dots per inch).
1060          * @param verticalDpi The vertical resolution in DPI (dots per inch).
1061          *
1062          * @throws IllegalArgumentException If the id is empty or the label is empty
1063          * or the horizontalDpi is less than or equal to zero or the verticalDpi is
1064          * less than or equal to zero.
1065          */
Resolution(String id, String label, int horizontalDpi, int verticalDpi)1066         public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
1067             if (TextUtils.isEmpty(id)) {
1068                 throw new IllegalArgumentException("id cannot be empty.");
1069             }
1070             if (TextUtils.isEmpty(label)) {
1071                 throw new IllegalArgumentException("label cannot be empty.");
1072             }
1073             if (horizontalDpi <= 0) {
1074                 throw new IllegalArgumentException("horizontalDpi "
1075                         + "cannot be less than or equal to zero.");
1076             }
1077             if (verticalDpi <= 0) {
1078                 throw new IllegalArgumentException("verticalDpi"
1079                        + " cannot be less than or equal to zero.");
1080             }
1081             mId = id;
1082             mLabel = label;
1083             mHorizontalDpi = horizontalDpi;
1084             mVerticalDpi = verticalDpi;
1085         }
1086 
1087         /**
1088          * Gets the unique resolution id. It is unique amongst other resolutions
1089          * supported by the printer.
1090          * <p>
1091          * This id is defined by the client that generated the resolution
1092          * instance and should not be interpreted by other parties.
1093          * </p>
1094          *
1095          * @return The unique resolution id.
1096          */
getId()1097         public String getId() {
1098             return mId;
1099         }
1100 
1101         /**
1102          * Gets the resolution human readable label.
1103          *
1104          * @return The human readable label.
1105          */
getLabel()1106         public String getLabel() {
1107             return mLabel;
1108         }
1109 
1110         /**
1111          * Gets the horizontal resolution in DPI (dots per inch).
1112          *
1113          * @return The horizontal resolution.
1114          */
getHorizontalDpi()1115         public int getHorizontalDpi() {
1116             return mHorizontalDpi;
1117         }
1118 
1119         /**
1120          * Gets the vertical resolution in DPI (dots per inch).
1121          *
1122          * @return The vertical resolution.
1123          */
getVerticalDpi()1124         public int getVerticalDpi() {
1125             return mVerticalDpi;
1126         }
1127 
writeToParcel(Parcel parcel)1128         void writeToParcel(Parcel parcel) {
1129             parcel.writeString(mId);
1130             parcel.writeString(mLabel);
1131             parcel.writeInt(mHorizontalDpi);
1132             parcel.writeInt(mVerticalDpi);
1133         }
1134 
createFromParcel(Parcel parcel)1135         static Resolution createFromParcel(Parcel parcel) {
1136             return new Resolution(
1137                     parcel.readString(),
1138                     parcel.readString(),
1139                     parcel.readInt(),
1140                     parcel.readInt());
1141         }
1142 
1143         @Override
hashCode()1144         public int hashCode() {
1145             final int prime = 31;
1146             int result = 1;
1147             result = prime * result + mHorizontalDpi;
1148             result = prime * result + mVerticalDpi;
1149             return result;
1150         }
1151 
1152         @Override
equals(Object obj)1153         public boolean equals(Object obj) {
1154             if (this == obj) {
1155                 return true;
1156             }
1157             if (obj == null) {
1158                 return false;
1159             }
1160             if (getClass() != obj.getClass()) {
1161                 return false;
1162             }
1163             Resolution other = (Resolution) obj;
1164             if (mHorizontalDpi != other.mHorizontalDpi) {
1165                 return false;
1166             }
1167             if (mVerticalDpi != other.mVerticalDpi) {
1168                 return false;
1169             }
1170             return true;
1171         }
1172 
1173         @Override
toString()1174         public String toString() {
1175             StringBuilder builder = new StringBuilder();
1176             builder.append("Resolution{");
1177             builder.append("id: ").append(mId);
1178             builder.append(", label: ").append(mLabel);
1179             builder.append(", horizontalDpi: ").append(mHorizontalDpi);
1180             builder.append(", verticalDpi: ").append(mVerticalDpi);
1181             builder.append("}");
1182             return builder.toString();
1183         }
1184     }
1185 
1186     /**
1187      * This class specifies content margins. Margins define the white space
1188      * around the content where the left margin defines the amount of white
1189      * space on the left of the content and so on.
1190      */
1191     public static final class Margins {
1192         public static final Margins NO_MARGINS = new Margins(0,  0,  0,  0);
1193 
1194         private final int mLeftMils;
1195         private final int mTopMils;
1196         private final int mRightMils;
1197         private final int mBottomMils;
1198 
1199         /**
1200          * Creates a new instance.
1201          *
1202          * @param leftMils The left margin in mils (thousands of an inch).
1203          * @param topMils The top margin in mils (thousands of an inch).
1204          * @param rightMils The right margin in mils (thousands of an inch).
1205          * @param bottomMils The bottom margin in mils (thousands of an inch).
1206          */
Margins(int leftMils, int topMils, int rightMils, int bottomMils)1207         public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
1208             mTopMils = topMils;
1209             mLeftMils = leftMils;
1210             mRightMils = rightMils;
1211             mBottomMils = bottomMils;
1212         }
1213 
1214         /**
1215          * Gets the left margin in mils (thousands of an inch).
1216          *
1217          * @return The left margin.
1218          */
getLeftMils()1219         public int getLeftMils() {
1220             return mLeftMils;
1221         }
1222 
1223         /**
1224          * Gets the top margin in mils (thousands of an inch).
1225          *
1226          * @return The top margin.
1227          */
getTopMils()1228         public int getTopMils() {
1229             return mTopMils;
1230         }
1231 
1232         /**
1233          * Gets the right margin in mils (thousands of an inch).
1234          *
1235          * @return The right margin.
1236          */
getRightMils()1237         public int getRightMils() {
1238             return mRightMils;
1239         }
1240 
1241         /**
1242          * Gets the bottom margin in mils (thousands of an inch).
1243          *
1244          * @return The bottom margin.
1245          */
getBottomMils()1246         public int getBottomMils() {
1247             return mBottomMils;
1248         }
1249 
writeToParcel(Parcel parcel)1250         void writeToParcel(Parcel parcel) {
1251             parcel.writeInt(mLeftMils);
1252             parcel.writeInt(mTopMils);
1253             parcel.writeInt(mRightMils);
1254             parcel.writeInt(mBottomMils);
1255         }
1256 
createFromParcel(Parcel parcel)1257         static Margins createFromParcel(Parcel parcel) {
1258             return new Margins(
1259                     parcel.readInt(),
1260                     parcel.readInt(),
1261                     parcel.readInt(),
1262                     parcel.readInt());
1263         }
1264 
1265         @Override
hashCode()1266         public int hashCode() {
1267             final int prime = 31;
1268             int result = 1;
1269             result = prime * result + mBottomMils;
1270             result = prime * result + mLeftMils;
1271             result = prime * result + mRightMils;
1272             result = prime * result + mTopMils;
1273             return result;
1274         }
1275 
1276         @Override
equals(Object obj)1277         public boolean equals(Object obj) {
1278             if (this == obj) {
1279                 return true;
1280             }
1281             if (obj == null) {
1282                 return false;
1283             }
1284             if (getClass() != obj.getClass()) {
1285                 return false;
1286             }
1287             Margins other = (Margins) obj;
1288             if (mBottomMils != other.mBottomMils) {
1289                 return false;
1290             }
1291             if (mLeftMils != other.mLeftMils) {
1292                 return false;
1293             }
1294             if (mRightMils != other.mRightMils) {
1295                 return false;
1296             }
1297             if (mTopMils != other.mTopMils) {
1298                 return false;
1299             }
1300             return true;
1301         }
1302 
1303         @Override
toString()1304         public String toString() {
1305             StringBuilder builder = new StringBuilder();
1306             builder.append("Margins{");
1307             builder.append("leftMils: ").append(mLeftMils);
1308             builder.append(", topMils: ").append(mTopMils);
1309             builder.append(", rightMils: ").append(mRightMils);
1310             builder.append(", bottomMils: ").append(mBottomMils);
1311             builder.append("}");
1312             return builder.toString();
1313         }
1314     }
1315 
colorModeToString(int colorMode)1316     static String colorModeToString(int colorMode) {
1317         switch (colorMode) {
1318             case COLOR_MODE_MONOCHROME: {
1319                 return "COLOR_MODE_MONOCHROME";
1320             }
1321             case COLOR_MODE_COLOR: {
1322                 return "COLOR_MODE_COLOR";
1323             }
1324             default: {
1325                 return "COLOR_MODE_UNKNOWN";
1326             }
1327         }
1328     }
1329 
duplexModeToString(int duplexMode)1330     static String duplexModeToString(int duplexMode) {
1331         switch (duplexMode) {
1332             case DUPLEX_MODE_NONE: {
1333                 return "DUPLEX_MODE_NONE";
1334             }
1335             case DUPLEX_MODE_LONG_EDGE: {
1336                 return "DUPLEX_MODE_LONG_EDGE";
1337             }
1338             case DUPLEX_MODE_SHORT_EDGE: {
1339                 return "DUPLEX_MODE_SHORT_EDGE";
1340             }
1341             default: {
1342                 return "DUPLEX_MODE_UNKNOWN";
1343             }
1344         }
1345     }
1346 
enforceValidColorMode(int colorMode)1347     static void enforceValidColorMode(int colorMode) {
1348         if ((colorMode & VALID_COLOR_MODES) == 0 || Integer.bitCount(colorMode) != 1) {
1349             throw new IllegalArgumentException("invalid color mode: " + colorMode);
1350         }
1351     }
1352 
enforceValidDuplexMode(int duplexMode)1353     static void enforceValidDuplexMode(int duplexMode) {
1354         if ((duplexMode & VALID_DUPLEX_MODES) == 0 || Integer.bitCount(duplexMode) != 1) {
1355             throw new IllegalArgumentException("invalid duplex mode: " + duplexMode);
1356         }
1357     }
1358 
1359     /**
1360      * Builder for creating {@link PrintAttributes}.
1361      */
1362     public static final class Builder {
1363         private final PrintAttributes mAttributes = new PrintAttributes();
1364 
1365         /**
1366          * Sets the media size.
1367          *
1368          * @param mediaSize The media size.
1369          * @return This builder.
1370          */
setMediaSize(MediaSize mediaSize)1371         public Builder setMediaSize(MediaSize mediaSize) {
1372             mAttributes.setMediaSize(mediaSize);
1373             return this;
1374         }
1375 
1376         /**
1377          * Sets the resolution.
1378          *
1379          * @param resolution The resolution.
1380          * @return This builder.
1381          */
setResolution(Resolution resolution)1382         public Builder setResolution(Resolution resolution) {
1383             mAttributes.setResolution(resolution);
1384             return this;
1385         }
1386 
1387         /**
1388          * Sets the minimal margins. If the content does not fit
1389          * these margins it will be clipped.
1390          *
1391          * @param margins The margins.
1392          * @return This builder.
1393          */
setMinMargins(Margins margins)1394         public Builder setMinMargins(Margins margins) {
1395             mAttributes.setMinMargins(margins);
1396             return this;
1397         }
1398 
1399         /**
1400          * Sets the color mode.
1401          *
1402          * @param colorMode A valid color mode or zero.
1403          * @return This builder.
1404          *
1405          * @see PrintAttributes#COLOR_MODE_MONOCHROME
1406          * @see PrintAttributes#COLOR_MODE_COLOR
1407          */
setColorMode(int colorMode)1408         public Builder setColorMode(int colorMode) {
1409             mAttributes.setColorMode(colorMode);
1410             return this;
1411         }
1412 
1413         /**
1414          * Sets the duplex mode.
1415          *
1416          * @param duplexMode A valid duplex mode or zero.
1417          * @return This builder.
1418          *
1419          * @see PrintAttributes#DUPLEX_MODE_NONE
1420          * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
1421          * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
1422          */
setDuplexMode(int duplexMode)1423         public Builder setDuplexMode(int duplexMode) {
1424             mAttributes.setDuplexMode(duplexMode);
1425             return this;
1426         }
1427 
1428         /**
1429          * Creates a new {@link PrintAttributes} instance.
1430          * <p>
1431          * If you do not specify a duplex mode, the default
1432          * {@link #DUPLEX_MODE_NONE} will be used.
1433          * </p>
1434          *
1435          * @return The new instance.
1436          */
build()1437         public PrintAttributes build() {
1438             return mAttributes;
1439         }
1440     }
1441 
1442     public static final Parcelable.Creator<PrintAttributes> CREATOR =
1443             new Creator<PrintAttributes>() {
1444         @Override
1445         public PrintAttributes createFromParcel(Parcel parcel) {
1446             return new PrintAttributes(parcel);
1447         }
1448 
1449         @Override
1450         public PrintAttributes[] newArray(int size) {
1451             return new PrintAttributes[size];
1452         }
1453     };
1454 }
1455