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