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