PrintAttributes.java revision fa77ece25a98810b6f56130d4a83c62b2e34c4f5
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.Log;
26
27import com.android.internal.R;
28
29/**
30 * This class represents the attributes of a print job.
31 */
32public final class PrintAttributes implements Parcelable {
33
34    /** Color mode: Monochrome color scheme, e.g. one color is used. */
35    public static final int COLOR_MODE_MONOCHROME = 1 << 0;
36    /** Color mode: Color color scheme, e.g. many colors are used. */
37    public static final int COLOR_MODE_COLOR = 1 << 1;
38
39    private static final int VALID_COLOR_MODES =
40            COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
41
42    private MediaSize mMediaSize;
43    private Resolution mResolution;
44    private Margins mMinMargins;
45
46    private int mColorMode;
47
48    PrintAttributes() {
49        /* hide constructor */
50    }
51
52    private PrintAttributes(Parcel parcel) {
53        mMediaSize = (parcel.readInt() ==  1) ? MediaSize.createFromParcel(parcel) : null;
54        mResolution = (parcel.readInt() ==  1) ? Resolution.createFromParcel(parcel) : null;
55        mMinMargins = (parcel.readInt() ==  1) ? Margins.createFromParcel(parcel) : null;
56        mColorMode = parcel.readInt();
57    }
58
59    /**
60     * Gets the media size.
61     *
62     * @return The media size or <code>null</code> if not set.
63     */
64    public MediaSize getMediaSize() {
65        return mMediaSize;
66    }
67
68    /**
69     * Sets the media size.
70     *
71     * @param The media size.
72     *
73     * @hide
74     */
75    public void setMediaSize(MediaSize mediaSize) {
76        mMediaSize = mediaSize;
77    }
78
79    /**
80     * Gets the resolution.
81     *
82     * @return The resolution or <code>null</code> if not set.
83     */
84    public Resolution getResolution() {
85        return mResolution;
86    }
87
88    /**
89     * Sets the resolution.
90     *
91     * @param The resolution.
92     *
93     * @hide
94     */
95    public void setResolution(Resolution resolution) {
96        mResolution = resolution;
97    }
98
99    /**
100     * Gets the minimal margins. If the content does not fit
101     * these margins it will be clipped.
102     *
103     * @return The margins or <code>null</code> if not set.
104     */
105    public Margins getMinMargins() {
106        return mMinMargins;
107    }
108
109    /**
110     * Sets the minimal margins. If the content does not fit
111     * these margins it will be clipped.
112     *
113     * @param The margins.
114     *
115     * @hide
116     */
117    public void setMinMargins(Margins margins) {
118        mMinMargins = margins;
119    }
120
121    /**
122     * Gets the color mode.
123     *
124     * @return The color mode or zero if not set.
125     *
126     * @see #COLOR_MODE_COLOR
127     * @see #COLOR_MODE_MONOCHROME
128     */
129    public int getColorMode() {
130        return mColorMode;
131    }
132
133    /**
134     * Sets the color mode.
135     *
136     * @param The color mode.
137     *
138     * @see #COLOR_MODE_MONOCHROME
139     * @see #COLOR_MODE_COLOR
140     *
141     * @hide
142     */
143    public void setColorMode(int colorMode) {
144        enforceValidColorMode(colorMode);
145        mColorMode = colorMode;
146    }
147
148    @Override
149    public void writeToParcel(Parcel parcel, int flags) {
150        if (mMediaSize != null) {
151            parcel.writeInt(1);
152            mMediaSize.writeToParcel(parcel);
153        } else {
154            parcel.writeInt(0);
155        }
156        if (mResolution != null) {
157            parcel.writeInt(1);
158            mResolution.writeToParcel(parcel);
159        } else {
160            parcel.writeInt(0);
161        }
162        if (mMinMargins != null) {
163            parcel.writeInt(1);
164            mMinMargins.writeToParcel(parcel);
165        } else {
166            parcel.writeInt(0);
167        }
168        parcel.writeInt(mColorMode);
169    }
170
171    @Override
172    public int describeContents() {
173        return 0;
174    }
175
176    @Override
177    public int hashCode() {
178        final int prime = 31;
179        int result = 1;
180        result = prime * result + mColorMode;
181        result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
182        result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
183        result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
184        return result;
185    }
186
187    @Override
188    public boolean equals(Object obj) {
189        if (this == obj) {
190            return true;
191        }
192        if (obj == null) {
193            return false;
194        }
195        if (getClass() != obj.getClass()) {
196            return false;
197        }
198        PrintAttributes other = (PrintAttributes) obj;
199        if (mColorMode != other.mColorMode) {
200            return false;
201        }
202        if (mMinMargins == null) {
203            if (other.mMinMargins != null) {
204                return false;
205            }
206        } else if (!mMinMargins.equals(other.mMinMargins)) {
207            return false;
208        }
209        if (mMediaSize == null) {
210            if (other.mMediaSize != null) {
211                return false;
212            }
213        } else if (!mMediaSize.equals(other.mMediaSize)) {
214            return false;
215        }
216        if (mResolution == null) {
217            if (other.mResolution != null) {
218                return false;
219            }
220        } else if (!mResolution.equals(other.mResolution)) {
221            return false;
222        }
223        return true;
224    }
225
226    @Override
227    public String toString() {
228        StringBuilder builder = new StringBuilder();
229        builder.append("PrintAttributes{");
230        builder.append("mediaSize: ").append(mMediaSize);
231        if (mMediaSize != null) {
232            builder.append(", orientation: ").append(mMediaSize.isPortrait()
233                    ? "portrait" : "landscape");
234        } else {
235            builder.append(", orientation: ").append("null");
236        }
237        builder.append(", resolution: ").append(mResolution);
238        builder.append(", minMargins: ").append(mMinMargins);
239        builder.append(", colorMode: ").append(colorModeToString(mColorMode));
240        builder.append("}");
241        return builder.toString();
242    }
243
244    /** hide */
245    public void clear() {
246        mMediaSize = null;
247        mResolution = null;
248        mMinMargins = null;
249        mColorMode = 0;
250    }
251
252    /**
253     * @hide
254     */
255    public void copyFrom(PrintAttributes other) {
256        mMediaSize = other.mMediaSize;
257        mResolution = other.mResolution;
258        mMinMargins = other.mMinMargins;
259        mColorMode = other.mColorMode;
260    }
261
262    /**
263     * This class specifies a supported media size.
264     */
265    public static final class MediaSize {
266        private static final String LOG_TAG = "MediaSize";
267
268        // TODO: Verify media sizes and add more standard ones.
269
270        // ISO sizes
271
272        /** ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") */
273        public static final MediaSize ISO_A0 =
274                new MediaSize("ISO_A0", "android", R.string.mediaSize_iso_a0, 33110, 46810);
275        /** ISO A1 media size: 594mm x 841mm (23.39" x 33.11") */
276        public static final MediaSize ISO_A1 =
277                new MediaSize("ISO_A1", "android", R.string.mediaSize_iso_a1, 23390, 33110);
278        /** ISO A2 media size: 420mm x 594mm (16.54" x 23.39") */
279        public static final MediaSize ISO_A2 =
280                new MediaSize("ISO_A2", "android", R.string.mediaSize_iso_a2, 16540, 23390);
281        /** ISO A3 media size: 297mm x 420mm (11.69" x 16.54") */
282        public static final MediaSize ISO_A3 =
283                new MediaSize("ISO_A3", "android", R.string.mediaSize_iso_a3, 11690, 16540);
284        /** ISO A4 media size: 210mm x 297mm (8.27" x 11.69") */
285        public static final MediaSize ISO_A4 =
286                new MediaSize("ISO_A4", "android", R.string.mediaSize_iso_a4, 8270, 11690);
287        /** ISO A5 media size: 148mm x 210mm (5.83" x 8.27") */
288        public static final MediaSize ISO_A5 =
289                new MediaSize("ISO_A5", "android", R.string.mediaSize_iso_a5, 5830, 8270);
290        /** ISO A6 media size: 105mm x 148mm (4.13" x 5.83") */
291        public static final MediaSize ISO_A6 =
292                new MediaSize("ISO_A6", "android", R.string.mediaSize_iso_a6, 4130, 5830);
293        /** ISO A7 media size: 74mm x 105mm (2.91" x 4.13") */
294        public static final MediaSize ISO_A7 =
295                new MediaSize("ISO_A7", "android", R.string.mediaSize_iso_a7, 2910, 4130);
296        /** ISO A8 media size: 52mm x 74mm (2.05" x 2.91") */
297        public static final MediaSize ISO_A8 =
298                new MediaSize("ISO_A8", "android", R.string.mediaSize_iso_a8, 2050, 2910);
299        /** ISO A9 media size: 37mm x 52mm (1.46" x 2.05") */
300        public static final MediaSize ISO_A9 =
301                new MediaSize("ISO_A9", "android", R.string.mediaSize_iso_a9, 1460, 2050);
302        /** ISO A10 media size: 26mm x 37mm (1.02" x 1.46") */
303        public static final MediaSize ISO_A10 =
304                new MediaSize("ISO_A10", "android", R.string.mediaSize_iso_a10, 1020, 1460);
305
306        /** ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") */
307        public static final MediaSize ISO_B0 =
308                new MediaSize("ISO_B0", "android", R.string.mediaSize_iso_b0, 39370, 55670);
309        /** ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") */
310        public static final MediaSize ISO_B1 =
311                new MediaSize("ISO_B1", "android", R.string.mediaSize_iso_b1, 27830, 39370);
312        /** ISO B2 media size: 500mm x 707mm (19.69" x 27.83") */
313        public static final MediaSize ISO_B2 =
314                new MediaSize("ISO_B2", "android", R.string.mediaSize_iso_b2, 19690, 27830);
315        /** ISO B3 media size: 353mm x 500mm (13.90" x 19.69") */
316        public static final MediaSize ISO_B3 =
317                new MediaSize("ISO_B3", "android", R.string.mediaSize_iso_b3, 13900, 19690);
318        /** ISO B4 media size: 250mm x 353mm (9.84" x 13.90") */
319        public static final MediaSize ISO_B4 =
320                new MediaSize("ISO_B4", "android", R.string.mediaSize_iso_b4, 9840, 13900);
321        /** ISO B5 media size: 176mm x 250mm (6.93" x 9.84") */
322        public static final MediaSize ISO_B5 =
323                new MediaSize("ISO_B5", "android", R.string.mediaSize_iso_b5, 6930, 9840);
324        /** ISO B6 media size: 125mm x 176mm (4.92" x 6.93") */
325        public static final MediaSize ISO_B6 =
326                new MediaSize("ISO_B6", "android", R.string.mediaSize_iso_b6, 4920, 6930);
327        /** ISO B7 media size: 88mm x 125mm (3.46" x 4.92") */
328        public static final MediaSize ISO_B7 =
329                new MediaSize("ISO_B7", "android", R.string.mediaSize_iso_b7, 3460, 4920);
330        /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") */
331        public static final MediaSize ISO_B8 =
332                new MediaSize("ISO_B8", "android", R.string.mediaSize_iso_b8, 2440, 3460);
333        /** ISO B9 media size: 44mm x 62mm (1.73" x 2.44") */
334        public static final MediaSize ISO_B9 =
335                new MediaSize("ISO_B9", "android", R.string.mediaSize_iso_b9, 1730, 2440);
336        /** ISO B10 media size: 31mm x 44mm (1.22" x 1.73") */
337        public static final MediaSize ISO_B10 =
338                new MediaSize("ISO_B10", "android", R.string.mediaSize_iso_b10, 1220, 1730);
339
340        /** ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") */
341        public static final MediaSize ISO_C0 =
342                new MediaSize("ISO_C0", "android", R.string.mediaSize_iso_c0, 36100, 51060);
343        /** ISO C1 media size: 648mm x 917mm (25.51" x 36.10") */
344        public static final MediaSize ISO_C1 =
345                new MediaSize("ISO_C1", "android", R.string.mediaSize_iso_c1, 25510, 36100);
346        /** ISO C2 media size: 458mm x 648mm (18.03" x 25.51") */
347        public static final MediaSize ISO_C2 =
348                new MediaSize("ISO_C2", "android", R.string.mediaSize_iso_c2, 18030, 25510);
349        /** ISO C3 media size: 324mm x 458mm (12.76" x 18.03") */
350        public static final MediaSize ISO_C3 =
351                new MediaSize("ISO_C3", "android", R.string.mediaSize_iso_c3, 12760, 18030);
352        /** ISO C4 media size: 229mm x 324mm (9.02" x 12.76") */
353        public static final MediaSize ISO_C4 =
354                new MediaSize("ISO_C4", "android", R.string.mediaSize_iso_c4, 9020, 12760);
355        /** ISO C5 media size: 162mm x 229mm (6.38" x 9.02") */
356        public static final MediaSize ISO_C5 =
357                new MediaSize("ISO_C5", "android", R.string.mediaSize_iso_c5, 6380, 9020);
358        /** ISO C6 media size: 114mm x 162mm (4.49" x 6.38") */
359        public static final MediaSize ISO_C6 =
360                new MediaSize("ISO_C6", "android", R.string.mediaSize_iso_c6, 4490, 6380);
361        /** ISO C7 media size: 81mm x 114mm (3.19" x 4.49") */
362        public static final MediaSize ISO_C7 =
363                new MediaSize("ISO_C7", "android", R.string.mediaSize_iso_c7, 3190, 4490);
364        /** ISO C8 media size: 57mm x 81mm (2.24" x 3.19") */
365        public static final MediaSize ISO_C8 =
366                new MediaSize("ISO_C8", "android", R.string.mediaSize_iso_c8, 2240, 3190);
367        /** ISO C9 media size: 40mm x 57mm (1.57" x 2.24") */
368        public static final MediaSize ISO_C9 =
369                new MediaSize("ISO_C9", "android", R.string.mediaSize_iso_c9, 1570, 2240);
370        /** ISO C10 media size: 28mm x 40mm (1.10" x 1.57") */
371        public static final MediaSize ISO_C10 =
372                new MediaSize("ISO_C10", "android", R.string.mediaSize_iso_c10, 1100, 1570);
373
374        // North America
375
376        /** North America Letter media size: 8.5" x 11" (279mm x 216mm) */
377        public static final MediaSize NA_LETTER =
378                new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
379        /** North America Government-Letter media size: 8.0" x 10.5" (203mm x 267mm) */
380        public static final MediaSize NA_GOVT_LETTER =
381                new MediaSize("NA_GOVT_LETTER", "android",
382                        R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
383        /** North America Legal media size: 8.5" x 14" (216mm x 356mm) */
384        public static final MediaSize NA_LEGAL =
385                new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
386        /** North America Junior Legal media size: 8.0" x 5.0" (203mm × 127mm) */
387        public static final MediaSize NA_JUNIOR_LEGAL =
388                new MediaSize("NA_JUNIOR_LEGAL", "android",
389                        R.string.mediaSize_na_junior_legal, 8000, 5000);
390        /** North America Ledger media size: 17" x 11" (432mm × 279mm) */
391        public static final MediaSize NA_LEDGER =
392                new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
393        /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
394        public static final MediaSize NA_TBLOID =
395                new MediaSize("NA_TABLOID", "android",
396                        R.string.mediaSize_na_tabloid, 11000, 17000);
397        /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
398        public static final MediaSize NA_INDEX_3X5 =
399                new MediaSize("NA_INDEX_3X5", "android",
400                        R.string.mediaSize_na_index_3x5, 3000, 5000);
401        /** North America Index Card 4x6 media size: 4" x 6" (102mm x 152mm) */
402        public static final MediaSize NA_INDEX_4X6 =
403                new MediaSize("NA_INDEX_4X6", "android",
404                        R.string.mediaSize_na_index_4x6, 4000, 6000);
405        /** North America Index Card 5x8 media size: 5" x 8" (127mm x 203mm) */
406        public static final MediaSize NA_INDEX_5X8 =
407                new MediaSize("NA_INDEX_5X8", "android",
408                        R.string.mediaSize_na_index_5x8, 5000, 8000);
409        /** North America Monarch media size: 7.25" x 10.5" (184mm x 267mm) */
410        public static final MediaSize NA_MONARCH =
411                new MediaSize("NA_MONARCH", "android",
412                        R.string.mediaSize_na_monarch, 7250, 10500);
413        /** North America Quarto media size: 8" x 10" (203mm x 254mm) */
414        public static final MediaSize NA_QUARTO =
415                new MediaSize("NA_QUARTO", "android",
416                        R.string.mediaSize_na_quarto, 8000, 10000);
417        /** North America Foolscap media size: 8" x 13" (203mm x 330mm) */
418        public static final MediaSize NA_FOOLSCAP =
419                new MediaSize("NA_FOOLSCAP", "android",
420                        R.string.mediaSize_na_foolscap, 8000, 13000);
421
422        // Chinese
423
424        /** Chinese ROC 8K media size: 270mm x 390mm (10.629" x 15.3543") */
425        public static final MediaSize ROC_8K =
426                new MediaSize("ROC_8K", "android",
427                        R.string.mediaSize_chinese_roc_8k, 10629, 15354);
428        /** Chinese ROC 16K media size: 195mm x 270mm (7.677" x 10.629") */
429        public static final MediaSize ROC_16K =
430                new MediaSize("ROC_16K", "android",
431                        R.string.mediaSize_chinese_roc_16k, 7677, 10629);
432
433        /** Chinese PRC 1 media size: 102mm x 165mm (4.015" x 6.496") */
434        public static final MediaSize PRC_1 =
435                new MediaSize("PRC_1", "android",
436                        R.string.mediaSize_chinese_prc_1, 4015, 6496);
437        /** Chinese PRC 2 media size: 102mm x 176mm (4.015" x 6.929") */
438        public static final MediaSize PRC_2 =
439                new MediaSize("PRC_2", "android",
440                        R.string.mediaSize_chinese_prc_2, 4015, 6929);
441        /** Chinese PRC 3 media size: 125mm x 176mm (4.921" x 6.929") */
442        public static final MediaSize PRC_3 =
443                new MediaSize("PRC_3", "android",
444                        R.string.mediaSize_chinese_prc_3, 4921, 6929);
445        /** Chinese PRC 4 media size: 110mm x 208mm (4.330" x 8.189") */
446        public static final MediaSize PRC_4 =
447                new MediaSize("PRC_4", "android",
448                        R.string.mediaSize_chinese_prc_4, 4330, 8189);
449        /** Chinese PRC 5 media size: 110mm x 220mm (4.330" x 8.661") */
450        public static final MediaSize PRC_5 =
451                new MediaSize("PRC_5", "android",
452                        R.string.mediaSize_chinese_prc_5, 4330, 8661);
453        /** Chinese PRC 6 media size: 120mm x 320mm (4.724" x 12.599") */
454        public static final MediaSize PRC_6 =
455                new MediaSize("PRC_6", "android",
456                        R.string.mediaSize_chinese_prc_6, 4724, 12599);
457        /** Chinese PRC 7 media size: 160mm x 230mm (6.299" x 9.055") */
458        public static final MediaSize PRC_7 =
459                new MediaSize("PRC_7", "android",
460                        R.string.mediaSize_chinese_prc_7, 6299, 9055);
461        /** Chinese PRC 8 media size: 120mm x 309mm (4.724" x 12.165") */
462        public static final MediaSize PRC_8 =
463                new MediaSize("PRC_8", "android",
464                        R.string.mediaSize_chinese_prc_8, 4724, 12165);
465        /** Chinese PRC 9 media size: 229mm x 324mm (9.016" x 12.756") */
466        public static final MediaSize PRC_9 =
467                new MediaSize("PRC_9", "android",
468                        R.string.mediaSize_chinese_prc_9, 9016, 12756);
469        /** Chinese PRC 10 media size: 324mm x 458mm (12.756" x 18.032") */
470        public static final MediaSize PRC_10 =
471                new MediaSize("PRC_10", "android",
472                        R.string.mediaSize_chinese_prc_10, 12756, 18032);
473
474        /** Chinese PRC 16k media size: 146mm x 215mm (5.749" x 8.465") */
475        public static final MediaSize PRC_16k =
476                new MediaSize("PRC_16k", "android",
477                        R.string.mediaSize_chinese_prc_16k, 5749, 8465);
478        /** Chinese Pa Kai media size: 267mm x 389mm (10.512" x 15.315") */
479        public static final MediaSize OM_PA_KAI =
480                new MediaSize("OM_PA_KAI", "android",
481                        R.string.mediaSize_chinese_om_pa_kai, 10512, 15315);
482        /** Chinese Dai Pa Kai media size: 275mm x 395mm (10.827" x 15.551") */
483        public static final MediaSize OM_DAI_PA_KAI =
484                new MediaSize("OM_DAI_PA_KAI", "android",
485                        R.string.mediaSize_chinese_om_dai_pa_kai, 10827, 15551);
486        /** Chinese Jurro Ku Kai media size: 198mm x 275mm (7.796" x 10.827") */
487        public static final MediaSize OM_JUURO_KU_KAI =
488                new MediaSize("OM_JUURO_KU_KAI", "android",
489                        R.string.mediaSize_chinese_om_jurro_ku_kai, 7796, 10827);
490
491        // Japanese
492
493        /** Japanese JIS B10 media size: 32mm x 45mm (1.259" x 1.772") */
494        public static final MediaSize JIS_B10 =
495                new MediaSize("JIS_B10", "android",
496                        R.string.mediaSize_japanese_jis_b10, 1259, 1772);
497        /** Japanese JIS B9 media size: 45mm x 64mm (1.772" x 2.52") */
498        public static final MediaSize JIS_B9 =
499                new MediaSize("JIS_B9", "android",
500                        R.string.mediaSize_japanese_jis_b9, 1772, 2520);
501        /** Japanese JIS B8 media size: 64mm x 91mm (2.52" x 3.583") */
502        public static final MediaSize JIS_B8 =
503                new MediaSize("JIS_B8", "android",
504                        R.string.mediaSize_japanese_jis_b8, 2520, 3583);
505        /** Japanese JIS B7 media size: 91mm x 128mm (3.583" x 5.049") */
506        public static final MediaSize JIS_B7 =
507                new MediaSize("JIS_B7", "android",
508                        R.string.mediaSize_japanese_jis_b7, 3583, 5049);
509        /** Japanese JIS B6 media size: 128mm x 182mm (5.049" x 7.165") */
510        public static final MediaSize JIS_B6 =
511                new MediaSize("JIS_B6", "android",
512                        R.string.mediaSize_japanese_jis_b6, 5049, 7165);
513        /** Japanese JIS B5 media size: 182mm x 257mm (7.165" x 10.118") */
514        public static final MediaSize JIS_B5 =
515                new MediaSize("JIS_B5", "android",
516                        R.string.mediaSize_japanese_jis_b5, 7165, 10118);
517        /** Japanese JIS B4 media size: 257mm x 364mm (10.118" x 14.331") */
518        public static final MediaSize JIS_B4 =
519                new MediaSize("JIS_B4", "android",
520                        R.string.mediaSize_japanese_jis_b4, 10118, 14331);
521        /** Japanese JIS B3 media size: 364mm x 515mm (14.331" x 20.276") */
522        public static final MediaSize JIS_B3 =
523                new MediaSize("JIS_B3", "android",
524                        R.string.mediaSize_japanese_jis_b3, 14331, 20276);
525        /** Japanese JIS B2 media size: 515mm x 728mm (20.276" x 28.661") */
526        public static final MediaSize JIS_B2 =
527                new MediaSize("JIS_B2", "android",
528                        R.string.mediaSize_japanese_jis_b2, 20276, 28661);
529        /** Japanese JIS B1 media size: 728mm x 1030mm (28.661" x 40.551") */
530        public static final MediaSize JIS_B1 =
531                new MediaSize("JIS_B1", "android",
532                        R.string.mediaSize_japanese_jis_b1, 28661, 40551);
533        /** Japanese JIS B0 media size: 1030mm x 1456mm (40.551" x 57.323") */
534        public static final MediaSize JIS_B0 =
535                new MediaSize("JIS_B0", "android",
536                        R.string.mediaSize_japanese_jis_b0, 40551, 57323);
537
538        /** Japanese JIS Exec media size: 216mm x 330mm (8.504" x 12.992") */
539        public static final MediaSize JIS_EXEC =
540                new MediaSize("JIS_EXEC", "android",
541                        R.string.mediaSize_japanese_jis_exec, 8504, 12992);
542
543        /** Japanese Chou4 media size: 90mm x 205mm (3.543" x 8.071") */
544        public static final MediaSize JPN_CHOU4 =
545                new MediaSize("JPN_CHOU4", "android",
546                        R.string.mediaSize_japanese_chou4, 3543, 8071);
547        /** Japanese Chou3 media size: 120mm x 235mm (4.724" x 9.252") */
548        public static final MediaSize JPN_CHOU3 =
549                new MediaSize("JPN_CHOU3", "android",
550                        R.string.mediaSize_japanese_chou3, 4724, 9252);
551        /** Japanese Chou2 media size: 111.1mm x 146mm (4.374" x 5.748") */
552        public static final MediaSize JPN_CHOU2 =
553                new MediaSize("JPN_CHOU2", "android",
554                        R.string.mediaSize_japanese_chou2, 4374, 5748);
555
556        /** Japanese Hagaki media size: 100mm x 148mm (3.937" x 5.827") */
557        public static final MediaSize JPN_HAGAKI =
558                new MediaSize("JPN_HAGAKI", "android",
559                        R.string.mediaSize_japanese_hagaki, 3937, 5827);
560        /** Japanese Oufuku media size: 148mm x 200mm (5.827" x 7.874") */
561        public static final MediaSize JPN_OUFUKU =
562                new MediaSize("JPN_OUFUKU", "android",
563                        R.string.mediaSize_japanese_oufuku, 5827, 7874);
564
565        /** Japanese Kahu media size: 240mm x 322.1mm (9.449" x 12.681") */
566        public static final MediaSize JPN_KAHU =
567                new MediaSize("JPN_KAHU", "android",
568                        R.string.mediaSize_japanese_kahu, 9449, 12681);
569        /** Japanese Kaku2 media size: 240mm x 332mm (9.449" x 13.071") */
570        public static final MediaSize JPN_KAKU2 =
571                new MediaSize("JPN_KAKU2", "android",
572                        R.string.mediaSize_japanese_kaku2, 9449, 13071);
573
574        /** Japanese You4 media size: 105mm x 235mm (4.134" x 9.252") */
575        public static final MediaSize JPN_YOU4 =
576                new MediaSize("JPN_YOU4", "android",
577                        R.string.mediaSize_japanese_you4, 4134, 9252);
578
579        private final String mId;
580        /**@hide */
581        public final String mLabel;
582        /**@hide */
583        public final String mPackageName;
584        /**@hide */
585        public final int mLabelResId;
586        private final int mWidthMils;
587        private final int mHeightMils;
588
589        /**
590         * Creates a new instance. This is the preferred constructor since
591         * it enables the media size label to be shown in a localized fashion
592         * on a locale change.
593         *
594         * @param id The unique media size id.
595         * @param packageName The name of the creating package.
596         * @param labelResId The resource if of a human readable label.
597         * @param widthMils The width in mils (thousands of an inch).
598         * @param heightMils The height in mils (thousands of an inch).
599         *
600         * @throws IllegalArgumentException If the id is empty.
601         * @throws IllegalArgumentException If the label is empty.
602         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
603         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
604         *
605         * @hide
606         */
607        public MediaSize(String id, String packageName, int labelResId,
608                int widthMils, int heightMils) {
609            if (TextUtils.isEmpty(id)) {
610                throw new IllegalArgumentException("id cannot be empty.");
611            }
612            if (TextUtils.isEmpty(packageName)) {
613                throw new IllegalArgumentException("packageName cannot be empty.");
614            }
615            if (labelResId <= 0) {
616                throw new IllegalArgumentException("labelResId must be greater than zero.");
617            }
618            if (widthMils <= 0) {
619                throw new IllegalArgumentException("widthMils "
620                        + "cannot be less than or equal to zero.");
621            }
622            if (heightMils <= 0) {
623                throw new IllegalArgumentException("heightMils "
624                       + "cannot be less than or euqual to zero.");
625            }
626            mPackageName = packageName;
627            mId = id;
628            mLabelResId = labelResId;
629            mWidthMils = widthMils;
630            mHeightMils = heightMils;
631            mLabel = null;
632        }
633
634        /**
635         * Creates a new instance.
636         *
637         * @param id The unique media size id.
638         * @param label The <strong>internationalized</strong> human readable label.
639         * @param widthMils The width in mils (thousands of an inch).
640         * @param heightMils The height in mils (thousands of an inch).
641         *
642         * @throws IllegalArgumentException If the id is empty.
643         * @throws IllegalArgumentException If the label is empty.
644         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
645         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
646         */
647        public MediaSize(String id, String label, int widthMils, int heightMils) {
648            if (TextUtils.isEmpty(id)) {
649                throw new IllegalArgumentException("id cannot be empty.");
650            }
651            if (TextUtils.isEmpty(label)) {
652                throw new IllegalArgumentException("label cannot be empty.");
653            }
654            if (widthMils <= 0) {
655                throw new IllegalArgumentException("widthMils "
656                        + "cannot be less than or equal to zero.");
657            }
658            if (heightMils <= 0) {
659                throw new IllegalArgumentException("heightMils "
660                       + "cannot be less than or euqual to zero.");
661            }
662            mId = id;
663            mLabel = label;
664            mWidthMils = widthMils;
665            mHeightMils = heightMils;
666            mLabelResId = 0;
667            mPackageName = null;
668        }
669
670        /** @hide */
671        public MediaSize(String id, String label, String packageName,
672                int widthMils, int heightMils, int labelResId) {
673            mPackageName = packageName;
674            mId = id;
675            mLabelResId = labelResId;
676            mWidthMils = widthMils;
677            mHeightMils = heightMils;
678            mLabel = label;
679        }
680
681        /**
682         * Gets the unique media size id.
683         *
684         * @return The unique media size id.
685         */
686        public String getId() {
687            return mId;
688        }
689
690        /**
691         * Gets the human readable media size label.
692         *
693         * @param packageManager The package manager for loading the label.
694         * @return The human readable label.
695         */
696        public String getLabel(PackageManager packageManager) {
697            if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
698                try {
699                    return packageManager.getResourcesForApplication(
700                            mPackageName).getString(mLabelResId);
701                } catch (NotFoundException nfe) {
702                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
703                            + " from package " + mPackageName);
704                } catch (NameNotFoundException nnfee) {
705                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
706                            + " from package " + mPackageName);
707                }
708            }
709            return mLabel;
710        }
711
712        /**
713         * Gets the media width in mils (thousands of an inch).
714         *
715         * @return The media width.
716         */
717        public int getWidthMils() {
718            return mWidthMils;
719        }
720
721        /**
722         * Gets the media height in mils (thousands of an inch).
723         *
724         * @return The media height.
725         */
726        public int getHeightMils() {
727            return mHeightMils;
728        }
729
730        /**
731         * Gets whether this media size is in portrait which is the
732         * height is greater or equal to the width.
733         *
734         * @return True if the media size is in portrait, false if
735         * it is in landscape.
736         */
737        public boolean isPortrait() {
738            return mHeightMils >= mWidthMils;
739        }
740
741        /**
742         * Returns a new media size in a portrait orientation
743         * which is the height is the greater dimension.
744         *
745         * @return New instance in landscape orientation.
746         */
747        public MediaSize asPortrait() {
748            return new MediaSize(mId, mLabel, mPackageName,
749                    Math.min(mWidthMils, mHeightMils),
750                    Math.max(mWidthMils, mHeightMils),
751                    mLabelResId);
752        }
753
754        /**
755         * Returns a new media size in a landscape orientation
756         * which is the height is the lesser dimension.
757         *
758         * @return New instance in landscape orientation.
759         */
760        public MediaSize asLandscape() {
761            return new MediaSize(mId, mLabel, mPackageName,
762                    Math.max(mWidthMils, mHeightMils),
763                    Math.min(mWidthMils, mHeightMils),
764                    mLabelResId);
765        }
766
767        void writeToParcel(Parcel parcel) {
768            parcel.writeString(mId);
769            parcel.writeString(mLabel);
770            parcel.writeString(mPackageName);
771            parcel.writeInt(mWidthMils);
772            parcel.writeInt(mHeightMils);
773            parcel.writeInt(mLabelResId);
774        }
775
776        static MediaSize createFromParcel(Parcel parcel) {
777            return new MediaSize(
778                    parcel.readString(),
779                    parcel.readString(),
780                    parcel.readString(),
781                    parcel.readInt(),
782                    parcel.readInt(),
783                    parcel.readInt());
784        }
785
786        @Override
787        public int hashCode() {
788            final int prime = 31;
789            int result = 1;
790            result = prime * result + mWidthMils;
791            result = prime * result + mHeightMils;
792            return result;
793        }
794
795        @Override
796        public boolean equals(Object obj) {
797            if (this == obj) {
798                return true;
799            }
800            if (obj == null) {
801                return false;
802            }
803            if (getClass() != obj.getClass()) {
804                return false;
805            }
806            MediaSize other = (MediaSize) obj;
807            if (mWidthMils != other.mWidthMils) {
808                return false;
809            }
810            if (mHeightMils != other.mHeightMils) {
811                return false;
812            }
813            return true;
814        }
815
816        @Override
817        public String toString() {
818            StringBuilder builder = new StringBuilder();
819            builder.append("MediaSize{");
820            builder.append("id: ").append(mId);
821            builder.append(", label: ").append(mLabel);
822            builder.append(", packageName: ").append(mPackageName);
823            builder.append(", heightMils: ").append(mHeightMils);
824            builder.append(", widthMils: ").append(mWidthMils);
825            builder.append(", labelResId: ").append(mLabelResId);
826            builder.append("}");
827            return builder.toString();
828        }
829    }
830
831    /**
832     * This class specifies a supported resolution in dpi (dots per inch).
833     */
834    public static final class Resolution {
835        private final String mId;
836        private final String mLabel;
837        private final int mHorizontalDpi;
838        private final int mVerticalDpi;
839
840        /**
841         * Creates a new instance.
842         *
843         * @param id The unique resolution id.
844         * @param label The <strong>internationalized</strong> human readable label.
845         * @param horizontalDpi The horizontal resolution in dpi.
846         * @param verticalDpi The vertical resolution in dpi.
847         *
848         * @throws IllegalArgumentException If the id is empty.
849         * @throws IllegalArgumentException If the label is empty.
850         * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
851         * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
852         */
853        public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
854            if (TextUtils.isEmpty(id)) {
855                throw new IllegalArgumentException("id cannot be empty.");
856            }
857            if (TextUtils.isEmpty(label)) {
858                throw new IllegalArgumentException("label cannot be empty.");
859            }
860            if (horizontalDpi <= 0) {
861                throw new IllegalArgumentException("horizontalDpi "
862                        + "cannot be less than or equal to zero.");
863            }
864            if (verticalDpi <= 0) {
865                throw new IllegalArgumentException("verticalDpi"
866                       + " cannot be less than or equal to zero.");
867            }
868            mId = id;
869            mLabel = label;
870            mHorizontalDpi = horizontalDpi;
871            mVerticalDpi = verticalDpi;
872        }
873
874        /**
875         * Gets the unique resolution id.
876         *
877         * @return The unique resolution id.
878         */
879        public String getId() {
880            return mId;
881        }
882
883        /**
884         * Gets the resolution human readable label.
885         *
886         * @return The human readable label.
887         */
888        public String getLabel() {
889            return mLabel;
890        }
891
892        /**
893         * Gets the vertical resolution in dpi.
894         *
895         * @return The horizontal resolution.
896         */
897        public int getHorizontalDpi() {
898            return mHorizontalDpi;
899        }
900
901        /**
902         * Gets the vertical resolution in dpi.
903         *
904         * @return The vertical resolution.
905         */
906        public int getVerticalDpi() {
907            return mVerticalDpi;
908        }
909
910        void writeToParcel(Parcel parcel) {
911            parcel.writeString(mId);
912            parcel.writeString(mLabel);
913            parcel.writeInt(mHorizontalDpi);
914            parcel.writeInt(mVerticalDpi);
915        }
916
917        static Resolution createFromParcel(Parcel parcel) {
918            return new Resolution(
919                    parcel.readString(),
920                    parcel.readString(),
921                    parcel.readInt(),
922                    parcel.readInt());
923        }
924
925        @Override
926        public int hashCode() {
927            final int prime = 31;
928            int result = 1;
929            result = prime * result + mHorizontalDpi;
930            result = prime * result + mVerticalDpi;
931            return result;
932        }
933
934        @Override
935        public boolean equals(Object obj) {
936            if (this == obj) {
937                return true;
938            }
939            if (obj == null) {
940                return false;
941            }
942            if (getClass() != obj.getClass()) {
943                return false;
944            }
945            Resolution other = (Resolution) obj;
946            if (mHorizontalDpi != other.mHorizontalDpi) {
947                return false;
948            }
949            if (mVerticalDpi != other.mVerticalDpi) {
950                return false;
951            }
952            return true;
953        }
954
955        @Override
956        public String toString() {
957            StringBuilder builder = new StringBuilder();
958            builder.append("Resolution{");
959            builder.append("id: ").append(mId);
960            builder.append(", label: ").append(mLabel);
961            builder.append(", horizontalDpi: ").append(mHorizontalDpi);
962            builder.append(", verticalDpi: ").append(mVerticalDpi);
963            builder.append("}");
964            return builder.toString();
965        }
966    }
967
968    /**
969     * This class specifies content margins.
970     */
971    public static final class Margins {
972        public static final Margins NO_MARGINS = new Margins(0,  0,  0,  0);
973
974        private final int mLeftMils;
975        private final int mTopMils;
976        private final int mRightMils;
977        private final int mBottomMils;
978
979        /**
980         * Creates a new instance.
981         *
982         * @param leftMils The left margin in mils (thousands of an inch).
983         * @param topMils The top margin in mils (thousands of an inch).
984         * @param rightMils The right margin in mils (thousands of an inch).
985         * @param bottomMils The bottom margin in mils (thousands of an inch).
986         */
987        public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
988            mTopMils = topMils;
989            mLeftMils = leftMils;
990            mRightMils = rightMils;
991            mBottomMils = bottomMils;
992        }
993
994        /**
995         * Gets the left margin in mils (thousands of an inch).
996         *
997         * @return The left margin.
998         */
999        public int getLeftMils() {
1000            return mLeftMils;
1001        }
1002
1003        /**
1004         * Gets the top margin in mils (thousands of an inch).
1005         *
1006         * @return The top margin.
1007         */
1008        public int getTopMils() {
1009            return mTopMils;
1010        }
1011
1012        /**
1013         * Gets the right margin in mils (thousands of an inch).
1014         *
1015         * @return The right margin.
1016         */
1017        public int getRightMils() {
1018            return mRightMils;
1019        }
1020
1021        /**
1022         * Gets the bottom margin in mils (thousands of an inch).
1023         *
1024         * @return The bottom margin.
1025         */
1026        public int getBottomMils() {
1027            return mBottomMils;
1028        }
1029
1030        void writeToParcel(Parcel parcel) {
1031            parcel.writeInt(mLeftMils);
1032            parcel.writeInt(mTopMils);
1033            parcel.writeInt(mRightMils);
1034            parcel.writeInt(mBottomMils);
1035        }
1036
1037        static Margins createFromParcel(Parcel parcel) {
1038            return new Margins(
1039                    parcel.readInt(),
1040                    parcel.readInt(),
1041                    parcel.readInt(),
1042                    parcel.readInt());
1043        }
1044
1045        @Override
1046        public int hashCode() {
1047            final int prime = 31;
1048            int result = 1;
1049            result = prime * result + mBottomMils;
1050            result = prime * result + mLeftMils;
1051            result = prime * result + mRightMils;
1052            result = prime * result + mTopMils;
1053            return result;
1054        }
1055
1056        @Override
1057        public boolean equals(Object obj) {
1058            if (this == obj) {
1059                return true;
1060            }
1061            if (obj == null) {
1062                return false;
1063            }
1064            if (getClass() != obj.getClass()) {
1065                return false;
1066            }
1067            Margins other = (Margins) obj;
1068            if (mBottomMils != other.mBottomMils) {
1069                return false;
1070            }
1071            if (mLeftMils != other.mLeftMils) {
1072                return false;
1073            }
1074            if (mRightMils != other.mRightMils) {
1075                return false;
1076            }
1077            if (mTopMils != other.mTopMils) {
1078                return false;
1079            }
1080            return true;
1081        }
1082
1083        @Override
1084        public String toString() {
1085            StringBuilder builder = new StringBuilder();
1086            builder.append("Margins{");
1087            builder.append("leftMils: ").append(mLeftMils);
1088            builder.append(", topMils: ").append(mTopMils);
1089            builder.append(", rightMils: ").append(mRightMils);
1090            builder.append(", bottomMils: ").append(mBottomMils);
1091            builder.append("}");
1092            return builder.toString();
1093        }
1094    }
1095
1096    static String colorModeToString(int colorMode) {
1097        switch (colorMode) {
1098            case COLOR_MODE_MONOCHROME: {
1099                return "COLOR_MODE_MONOCHROME";
1100            }
1101            case COLOR_MODE_COLOR: {
1102                return "COLOR_MODE_COLOR";
1103            }
1104            default:
1105                return "COLOR_MODE_UNKNOWN";
1106        }
1107    }
1108
1109    static void enforceValidColorMode(int colorMode) {
1110        if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) {
1111            throw new IllegalArgumentException("invalid color mode: " + colorMode);
1112        }
1113    }
1114
1115    /**
1116     * Builder for creating {@link PrintAttributes}.
1117     */
1118    public static final class Builder {
1119        private final PrintAttributes mAttributes = new PrintAttributes();
1120
1121        /**
1122         * Sets the media size.
1123         *
1124         * @param mediaSize The media size.
1125         * @return This builder.
1126         */
1127        public Builder setMediaSize(MediaSize mediaSize) {
1128            mAttributes.setMediaSize(mediaSize);
1129            return this;
1130        }
1131
1132        /**
1133         * Sets the resolution.
1134         *
1135         * @param resolution The resolution.
1136         * @return This builder.
1137         */
1138        public Builder setResolution(Resolution resolution) {
1139            mAttributes.setResolution(resolution);
1140            return this;
1141        }
1142
1143        /**
1144         * Sets the minimal margins. If the content does not fit
1145         * these margins it will be clipped.
1146         *
1147         * @param margins The margins.
1148         * @return This builder.
1149         */
1150        public Builder setMinMargins(Margins margins) {
1151            mAttributes.setMinMargins(margins);
1152            return this;
1153        }
1154
1155        /**
1156         * Sets the color mode.
1157         *
1158         * @param colorMode A valid color mode or zero.
1159         * @return This builder.
1160         *
1161         * @see PrintAttributes#COLOR_MODE_MONOCHROME
1162         * @see PrintAttributes#COLOR_MODE_COLOR
1163         */
1164        public Builder setColorMode(int colorMode) {
1165            if (Integer.bitCount(colorMode) > 1) {
1166                throw new IllegalArgumentException("can specify at most one colorMode bit.");
1167            }
1168            mAttributes.setColorMode(colorMode);
1169            return this;
1170        }
1171
1172        /**
1173         * Creates a new {@link PrintAttributes} instance.
1174         *
1175         * @return The new instance.
1176         */
1177        public PrintAttributes build() {
1178            return mAttributes;
1179        }
1180    }
1181
1182    public static final Parcelable.Creator<PrintAttributes> CREATOR =
1183            new Creator<PrintAttributes>() {
1184        @Override
1185        public PrintAttributes createFromParcel(Parcel parcel) {
1186            return new PrintAttributes(parcel);
1187        }
1188
1189        @Override
1190        public PrintAttributes[] newArray(int size) {
1191            return new PrintAttributes[size];
1192        }
1193    };
1194}
1195