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