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