PrintAttributes.java revision 773f54de3de9bce7b6f915aa47ed686b161d77aa
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 mMargins;
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        mMargins = (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 margins.
101     *
102     * @return The margins or <code>null</code> if not set.
103     */
104    public Margins getMargins() {
105        return mMargins;
106    }
107
108    /**
109     * Sets the margins.
110     *
111     * @param The margins.
112     *
113     * @hide
114     */
115    public void setMargins(Margins margins) {
116        mMargins = margins;
117    }
118
119    /**
120     * Gets the color mode.
121     *
122     * @return The color mode or zero if not set.
123     *
124     * @see #COLOR_MODE_COLOR
125     * @see #COLOR_MODE_MONOCHROME
126     */
127    public int getColorMode() {
128        return mColorMode;
129    }
130
131    /**
132     * Sets the color mode.
133     *
134     * @param The color mode.
135     *
136     * @see #COLOR_MODE_MONOCHROME
137     * @see #COLOR_MODE_COLOR
138     *
139     * @hide
140     */
141    public void setColorMode(int colorMode) {
142        enforceValidColorMode(colorMode);
143        mColorMode = colorMode;
144    }
145
146    @Override
147    public void writeToParcel(Parcel parcel, int flags) {
148        if (mMediaSize != null) {
149            parcel.writeInt(1);
150            mMediaSize.writeToParcel(parcel);
151        } else {
152            parcel.writeInt(0);
153        }
154        if (mResolution != null) {
155            parcel.writeInt(1);
156            mResolution.writeToParcel(parcel);
157        } else {
158            parcel.writeInt(0);
159        }
160        if (mMargins != null) {
161            parcel.writeInt(1);
162            mMargins.writeToParcel(parcel);
163        } else {
164            parcel.writeInt(0);
165        }
166        parcel.writeInt(mColorMode);
167    }
168
169    @Override
170    public int describeContents() {
171        return 0;
172    }
173
174    @Override
175    public int hashCode() {
176        final int prime = 31;
177        int result = 1;
178        result = prime * result + mColorMode;
179        result = prime * result + ((mMargins == null) ? 0 : mMargins.hashCode());
180        result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
181        result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
182        return result;
183    }
184
185    @Override
186    public boolean equals(Object obj) {
187        if (this == obj) {
188            return true;
189        }
190        if (obj == null) {
191            return false;
192        }
193        if (getClass() != obj.getClass()) {
194            return false;
195        }
196        PrintAttributes other = (PrintAttributes) obj;
197        if (mColorMode != other.mColorMode) {
198            return false;
199        }
200        if (mMargins == null) {
201            if (other.mMargins != null) {
202                return false;
203            }
204        } else if (!mMargins.equals(other.mMargins)) {
205            return false;
206        }
207        if (mMediaSize == null) {
208            if (other.mMediaSize != null) {
209                return false;
210            }
211        } else if (!mMediaSize.equals(other.mMediaSize)) {
212            return false;
213        }
214        if (mResolution == null) {
215            if (other.mResolution != null) {
216                return false;
217            }
218        } else if (!mResolution.equals(other.mResolution)) {
219            return false;
220        }
221        return true;
222    }
223
224    @Override
225    public String toString() {
226        StringBuilder builder = new StringBuilder();
227        builder.append("PrintAttributes{");
228        builder.append("mediaSize: ").append(mMediaSize);
229        builder.append(", resolution: ").append(mResolution);
230        builder.append(", margins: ").append(mMargins);
231        builder.append(", colorMode: ").append(colorModeToString(mColorMode));
232        builder.append("}");
233        return builder.toString();
234    }
235
236    /** hide */
237    public void clear() {
238        mMediaSize = null;
239        mResolution = null;
240        mMargins = null;
241        mColorMode = 0;
242    }
243
244    /**
245     * @hide
246     */
247    public void copyFrom(PrintAttributes other) {
248        mMediaSize = other.mMediaSize;
249        mResolution = other.mResolution;
250        mMargins = other.mMargins;
251        mColorMode = other.mColorMode;
252    }
253
254    /**
255     * This class specifies a supported media size.
256     */
257    public static final class MediaSize {
258        private static final String LOG_TAG = "MediaSize";
259
260        // TODO: Verify media sizes and add more standard ones.
261
262        // ISO sizes
263
264        /** ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") */
265        public static final MediaSize ISO_A0 =
266                new MediaSize("ISO_A0", "android", R.string.mediaSize_iso_a0, 33110, 46810);
267        /** ISO A1 media size: 594mm x 841mm (23.39" x 33.11") */
268        public static final MediaSize ISO_A1 =
269                new MediaSize("ISO_A1", "android", R.string.mediaSize_iso_a1, 23390, 33110);
270        /** ISO A2 media size: 420mm x 594mm (16.54" x 23.39") */
271        public static final MediaSize ISO_A2 =
272                new MediaSize("ISO_A2", "android", R.string.mediaSize_iso_a2, 16540, 23390);
273        /** ISO A3 media size: 297mm x 420mm (11.69" x 16.54") */
274        public static final MediaSize ISO_A3 =
275                new MediaSize("ISO_A3", "android", R.string.mediaSize_iso_a3, 11690, 16540);
276        /** ISO A4 media size: 210mm x 297mm (8.27" x 11.69") */
277        public static final MediaSize ISO_A4 =
278                new MediaSize("ISO_A4", "android", R.string.mediaSize_iso_a4, 8270, 11690);
279        /** ISO A5 media size: 148mm x 210mm (5.83" x 8.27") */
280        public static final MediaSize ISO_A5 =
281                new MediaSize("ISO_A5", "android", R.string.mediaSize_iso_a5, 5830, 8270);
282        /** ISO A6 media size: 105mm x 148mm (4.13" x 5.83") */
283        public static final MediaSize ISO_A6 =
284                new MediaSize("ISO_A6", "android", R.string.mediaSize_iso_a6, 4130, 5830);
285        /** ISO A7 media size: 74mm x 105mm (2.91" x 4.13") */
286        public static final MediaSize ISO_A7 =
287                new MediaSize("ISO_A7", "android", R.string.mediaSize_iso_a7, 2910, 4130);
288        /** ISO A8 media size: 52mm x 74mm (2.05" x 2.91") */
289        public static final MediaSize ISO_A8 =
290                new MediaSize("ISO_A8", "android", R.string.mediaSize_iso_a8, 2050, 2910);
291        /** ISO A9 media size: 37mm x 52mm (1.46" x 2.05") */
292        public static final MediaSize ISO_A9 =
293                new MediaSize("ISO_A9", "android", R.string.mediaSize_iso_a9, 1460, 2050);
294        /** ISO A10 media size: 26mm x 37mm (1.02" x 1.46") */
295        public static final MediaSize ISO_A10 =
296                new MediaSize("ISO_A10", "android", R.string.mediaSize_iso_a10, 1020, 1460);
297
298        /** ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") */
299        public static final MediaSize ISO_B0 =
300                new MediaSize("ISO_B0", "android", R.string.mediaSize_iso_b0, 39370, 55670);
301        /** ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") */
302        public static final MediaSize ISO_B1 =
303                new MediaSize("ISO_B1", "android", R.string.mediaSize_iso_b1, 27830, 39370);
304        /** ISO B2 media size: 500mm x 707mm (19.69" x 27.83") */
305        public static final MediaSize ISO_B2 =
306                new MediaSize("ISO_B2", "android", R.string.mediaSize_iso_b2, 19690, 27830);
307        /** ISO B3 media size: 353mm x 500mm (13.90" x 19.69") */
308        public static final MediaSize ISO_B3 =
309                new MediaSize("ISO_B3", "android", R.string.mediaSize_iso_b3, 13900, 19690);
310        /** ISO B4 media size: 250mm x 353mm (9.84" x 13.90") */
311        public static final MediaSize ISO_B4 =
312                new MediaSize("ISO_B4", "android", R.string.mediaSize_iso_b4, 9840, 13900);
313        /** ISO B5 media size: 176mm x 250mm (6.93" x 9.84") */
314        public static final MediaSize ISO_B5 =
315                new MediaSize("ISO_B5", "android", R.string.mediaSize_iso_b5, 6930, 9840);
316        /** ISO B6 media size: 125mm x 176mm (4.92" x 6.93") */
317        public static final MediaSize ISO_B6 =
318                new MediaSize("ISO_B6", "android", R.string.mediaSize_iso_b6, 4920, 6930);
319        /** ISO B7 media size: 88mm x 125mm (3.46" x 4.92") */
320        public static final MediaSize ISO_B7 =
321                new MediaSize("ISO_B7", "android", R.string.mediaSize_iso_b7, 3460, 4920);
322        /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") */
323        public static final MediaSize ISO_B8 =
324                new MediaSize("ISO_B8", "android", R.string.mediaSize_iso_b8, 2440, 3460);
325        /** ISO B9 media size: 44mm x 62mm (1.73" x 2.44") */
326        public static final MediaSize ISO_B9 =
327                new MediaSize("ISO_B9", "android", R.string.mediaSize_iso_b9, 1730, 2440);
328        /** ISO B10 media size: 31mm x 44mm (1.22" x 1.73") */
329        public static final MediaSize ISO_B10 =
330                new MediaSize("ISO_B10", "android", R.string.mediaSize_iso_b10, 1220, 1730);
331
332        /** ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") */
333        public static final MediaSize ISO_C0 =
334                new MediaSize("ISO_C0", "android", R.string.mediaSize_iso_c0, 36100, 51060);
335        /** ISO C1 media size: 648mm x 917mm (25.51" x 36.10") */
336        public static final MediaSize ISO_C1 =
337                new MediaSize("ISO_C1", "android", R.string.mediaSize_iso_c1, 25510, 36100);
338        /** ISO C2 media size: 458mm x 648mm (18.03" x 25.51") */
339        public static final MediaSize ISO_C2 =
340                new MediaSize("ISO_C2", "android", R.string.mediaSize_iso_c2, 18030, 25510);
341        /** ISO C3 media size: 324mm x 458mm (12.76" x 18.03") */
342        public static final MediaSize ISO_C3 =
343                new MediaSize("ISO_C3", "android", R.string.mediaSize_iso_c3, 12760, 18030);
344        /** ISO C4 media size: 229mm x 324mm (9.02" x 12.76") */
345        public static final MediaSize ISO_C4 =
346                new MediaSize("ISO_C4", "android", R.string.mediaSize_iso_c4, 9020, 12760);
347        /** ISO C5 media size: 162mm x 229mm (6.38" x 9.02") */
348        public static final MediaSize ISO_C5 =
349                new MediaSize("ISO_C5", "android", R.string.mediaSize_iso_c5, 6380, 9020);
350        /** ISO C6 media size: 114mm x 162mm (4.49" x 6.38") */
351        public static final MediaSize ISO_C6 =
352                new MediaSize("ISO_C6", "android", R.string.mediaSize_iso_c6, 4490, 6380);
353        /** ISO C7 media size: 81mm x 114mm (3.19" x 4.49") */
354        public static final MediaSize ISO_C7 =
355                new MediaSize("ISO_C7", "android", R.string.mediaSize_iso_c7, 3190, 4490);
356        /** ISO C8 media size: 57mm x 81mm (2.24" x 3.19") */
357        public static final MediaSize ISO_C8 =
358                new MediaSize("ISO_C8", "android", R.string.mediaSize_iso_c8, 2240, 3190);
359        /** ISO C9 media size: 40mm x 57mm (1.57" x 2.24") */
360        public static final MediaSize ISO_C9 =
361                new MediaSize("ISO_C9", "android", R.string.mediaSize_iso_c9, 1570, 2240);
362        /** ISO C10 media size: 28mm x 40mm (1.10" x 1.57") */
363        public static final MediaSize ISO_C10 =
364                new MediaSize("ISO_C10", "android", R.string.mediaSize_iso_c10, 1100, 1570);
365
366        // North America
367
368        /** North America Letter media size: 8.5" x 11" */
369        public static final MediaSize NA_LETTER =
370                new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
371        /** North America Government-Letter media size: 8.0" x 10.5" */
372        public static final MediaSize NA_GOVT_LETTER =
373                new MediaSize("NA_GOVT_LETTER", "android",
374                        R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
375        /** North America Legal media size: 8.5" x 14" */
376        public static final MediaSize NA_LEGAL =
377                new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
378        /** North America Junior Legal media size: 8.0" x 5.0" */
379        public static final MediaSize NA_JUNIOR_LEGAL =
380                new MediaSize("NA_JUNIOR_LEGAL", "android",
381                        R.string.mediaSize_na_junior_legal, 8000, 5000);
382        /** North America Ledger media size: 17" x 11" */
383        public static final MediaSize NA_LEDGER =
384                new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
385        /** North America Tabloid media size: 11" x 17" */
386        public static final MediaSize NA_TBLOID =
387                new MediaSize("NA_TABLOID", "android",
388                        R.string.mediaSize_na_tabloid, 11000, 17000);
389
390        private final String mId;
391        /**@hide */
392        public final String mLabel;
393        /**@hide */
394        public final String mPackageName;
395        /**@hide */
396        public final int mLabelResId;
397        private final int mWidthMils;
398        private final int mHeightMils;
399
400        /**
401         * Creates a new instance. This is the preferred constructor since
402         * it enables the media size label to be shown in a localized fashion
403         * on a locale change.
404         *
405         * @param id The unique media size id.
406         * @param packageName The name of the creating package.
407         * @param labelResId The resource if of a human readable label.
408         * @param widthMils The width in mils (thousands of an inch).
409         * @param heightMils The height in mils (thousands of an inch).
410         *
411         * @throws IllegalArgumentException If the id is empty.
412         * @throws IllegalArgumentException If the label is empty.
413         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
414         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
415         */
416        public MediaSize(String id, String packageName, int labelResId,
417                int widthMils, int heightMils) {
418            if (TextUtils.isEmpty(id)) {
419                throw new IllegalArgumentException("id cannot be empty.");
420            }
421            if (TextUtils.isEmpty(packageName)) {
422                throw new IllegalArgumentException("packageName cannot be empty.");
423            }
424            if (labelResId <= 0) {
425                throw new IllegalArgumentException("labelResId must be greater than zero.");
426            }
427            if (widthMils <= 0) {
428                throw new IllegalArgumentException("widthMils "
429                        + "cannot be less than or equal to zero.");
430            }
431            if (heightMils <= 0) {
432                throw new IllegalArgumentException("heightMils "
433                       + "cannot be less than or euqual to zero.");
434            }
435            mPackageName = packageName;
436            mId = id;
437            mLabelResId = labelResId;
438            mWidthMils = widthMils;
439            mHeightMils = heightMils;
440            mLabel = null;
441        }
442
443        /**
444         * Creates a new instance. You should use this constructor as a fallback
445         * in cases when you do not have a localized string for the label.
446         *
447         * @param id The unique media size id.
448         * @param label The <strong>internationalized</strong> human readable label.
449         * @param widthMils The width in mils (thousands of an inch).
450         * @param heightMils The height in mils (thousands of an inch).
451         *
452         * @throws IllegalArgumentException If the id is empty.
453         * @throws IllegalArgumentException If the label is empty.
454         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
455         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
456         */
457        public MediaSize(String id, String label, int widthMils, int heightMils) {
458            if (TextUtils.isEmpty(id)) {
459                throw new IllegalArgumentException("id cannot be empty.");
460            }
461            if (TextUtils.isEmpty(label)) {
462                throw new IllegalArgumentException("label cannot be empty.");
463            }
464            if (widthMils <= 0) {
465                throw new IllegalArgumentException("widthMils "
466                        + "cannot be less than or equal to zero.");
467            }
468            if (heightMils <= 0) {
469                throw new IllegalArgumentException("heightMils "
470                       + "cannot be less than or euqual to zero.");
471            }
472            mId = id;
473            mLabel = label;
474            mWidthMils = widthMils;
475            mHeightMils = heightMils;
476            mLabelResId = 0;
477            mPackageName = null;
478        }
479
480        /** @hide */
481        public MediaSize(String id, String label, String packageName,
482                int widthMils, int heightMils, int labelResId) {
483            mPackageName = packageName;
484            mId = id;
485            mLabelResId = labelResId;
486            mWidthMils = widthMils;
487            mHeightMils = heightMils;
488            mLabel = label;
489        }
490
491        /**
492         * Gets the unique media size id.
493         *
494         * @return The unique media size id.
495         */
496        public String getId() {
497            return mId;
498        }
499
500        /**
501         * Gets the human readable media size label.
502         *
503         * @param packageManager The package manager for loading the label.
504         * @return The human readable label.
505         */
506        public String getLabel(PackageManager packageManager) {
507            if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
508                try {
509                    return packageManager.getResourcesForApplication(
510                            mPackageName).getString(mLabelResId);
511                } catch (NotFoundException nfe) {
512                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
513                            + " from package " + mPackageName);
514                } catch (NameNotFoundException nnfee) {
515                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
516                            + " from package " + mPackageName);
517                }
518            }
519            return mLabel;
520        }
521
522        /**
523         * Gets the media width in mils (thousands of an inch).
524         *
525         * @return The media width.
526         */
527        public int getWidthMils() {
528            return mWidthMils;
529        }
530
531        /**
532         * Gets the media height in mils (thousands of an inch).
533         *
534         * @return The media height.
535         */
536        public int getHeightMils() {
537            return mHeightMils;
538        }
539
540        /**
541         * Gets whether this media size is in portrait which is the
542         * height is greater or equal to the width.
543         *
544         * @return True if the media size is in portrait, false if
545         * it is in landscape.
546         */
547        public boolean isPortrait() {
548            return mHeightMils >= mWidthMils;
549        }
550
551        /**
552         * Returns a new media size in a portrait orientation
553         * which is the height is the lesser dimension.
554         *
555         * @return New instance in landscape orientation.
556         */
557        public MediaSize asPortrait() {
558            if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
559                return new MediaSize(mId, mPackageName, mLabelResId,
560                        Math.min(mWidthMils, mHeightMils),
561                        Math.max(mWidthMils, mHeightMils));
562            } else {
563                return new MediaSize(mId, mLabel,
564                        Math.min(mWidthMils, mHeightMils),
565                        Math.max(mWidthMils, mHeightMils));
566            }
567        }
568
569        /**
570         * Returns a new media size in a landscape orientation
571         * which is the height is the greater dimension.
572         *
573         * @return New instance in landscape orientation.
574         */
575        public MediaSize asLandscape() {
576            return new MediaSize(mId, mLabel,
577                    Math.max(mWidthMils, mHeightMils),
578                    Math.min(mWidthMils, mHeightMils));
579        }
580
581        void writeToParcel(Parcel parcel) {
582            parcel.writeString(mId);
583            parcel.writeString(mLabel);
584            parcel.writeString(mPackageName);
585            parcel.writeInt(mWidthMils);
586            parcel.writeInt(mHeightMils);
587            parcel.writeInt(mLabelResId);
588        }
589
590        static MediaSize createFromParcel(Parcel parcel) {
591            return new MediaSize(
592                    parcel.readString(),
593                    parcel.readString(),
594                    parcel.readString(),
595                    parcel.readInt(),
596                    parcel.readInt(),
597                    parcel.readInt());
598        }
599
600        @Override
601        public int hashCode() {
602            final int prime = 31;
603            int result = 1;
604            result = prime * result + ((mId == null) ? 0 : mId.hashCode());
605            result = prime * result + mWidthMils;
606            result = prime * result + mHeightMils;
607            return result;
608        }
609
610        @Override
611        public boolean equals(Object obj) {
612            if (this == obj) {
613                return true;
614            }
615            if (obj == null) {
616                return false;
617            }
618            if (getClass() != obj.getClass()) {
619                return false;
620            }
621            MediaSize other = (MediaSize) obj;
622            if (!TextUtils.equals(mId, other.mId)) {
623                return false;
624            }
625            if (mWidthMils != other.mWidthMils) {
626                return false;
627            }
628            if (mHeightMils != other.mHeightMils) {
629                return false;
630            }
631            return true;
632        }
633
634        @Override
635        public String toString() {
636            StringBuilder builder = new StringBuilder();
637            builder.append("MediaSize{");
638            builder.append("id: ").append(mId);
639            builder.append(", label: ").append(mLabel);
640            builder.append(", packageName: ").append(mPackageName);
641            builder.append(", heightMils: ").append(mHeightMils);
642            builder.append(", widthMils: ").append(mWidthMils);
643            builder.append(", labelResId: ").append(mLabelResId);
644            builder.append("}");
645            return builder.toString();
646        }
647    }
648
649    /**
650     * This class specifies a supported resolution in dpi (dots per inch).
651     */
652    public static final class Resolution {
653        private static final String LOG_TAG = "Resolution";
654
655        private final String mId;
656        /**@hide */
657        public final String mLabel;
658        /**@hide */
659        public final String mPackageName;
660        /**@hide */
661        public final int mLabelResId;
662        private final int mHorizontalDpi;
663        private final int mVerticalDpi;
664
665        /**
666         * Creates a new instance. This is the preferred constructor since
667         * it enables the resolution label to be shown in a localized fashion
668         * on a locale change.
669         *
670         * @param id The unique resolution id.
671         * @param packageName The name of the creating package.
672         * @param labelResId The resource id of a human readable label.
673         * @param horizontalDpi The horizontal resolution in dpi.
674         * @param verticalDpi The vertical resolution in dpi.
675         *
676         * @throws IllegalArgumentException If the id is empty.
677         * @throws IllegalArgumentException If the label is empty.
678         * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
679         * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
680         */
681        public Resolution(String id, String packageName, int labelResId,
682                int horizontalDpi, int verticalDpi) {
683            if (TextUtils.isEmpty(id)) {
684                throw new IllegalArgumentException("id cannot be empty.");
685            }
686            if (TextUtils.isEmpty(packageName)) {
687                throw new IllegalArgumentException("packageName cannot be empty.");
688            }
689            if (labelResId <= 0) {
690                throw new IllegalArgumentException("labelResId must be greater than zero.");
691            }
692            if (horizontalDpi <= 0) {
693                throw new IllegalArgumentException("horizontalDpi "
694                        + "cannot be less than or equal to zero.");
695            }
696            if (verticalDpi <= 0) {
697                throw new IllegalArgumentException("verticalDpi"
698                       + " cannot be less than or equal to zero.");
699            }
700            mId = id;
701            mPackageName = packageName;
702            mLabelResId = labelResId;
703            mHorizontalDpi = horizontalDpi;
704            mVerticalDpi = verticalDpi;
705            mLabel = null;
706        }
707
708        /**
709         * Creates a new instance. You should use this constructor as a fallback
710         * in cases when you do not have a localized string for the label.
711         *
712         * @param id The unique resolution id.
713         * @param label The <strong>internationalized</strong> human readable label.
714         * @param horizontalDpi The horizontal resolution in dpi.
715         * @param verticalDpi The vertical resolution in dpi.
716         *
717         * @throws IllegalArgumentException If the id is empty.
718         * @throws IllegalArgumentException If the label is empty.
719         * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
720         * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
721         */
722        public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
723            if (TextUtils.isEmpty(id)) {
724                throw new IllegalArgumentException("id cannot be empty.");
725            }
726            if (TextUtils.isEmpty(label)) {
727                throw new IllegalArgumentException("label cannot be empty.");
728            }
729            if (horizontalDpi <= 0) {
730                throw new IllegalArgumentException("horizontalDpi "
731                        + "cannot be less than or equal to zero.");
732            }
733            if (verticalDpi <= 0) {
734                throw new IllegalArgumentException("verticalDpi"
735                       + " cannot be less than or equal to zero.");
736            }
737            mId = id;
738            mLabel = label;
739            mHorizontalDpi = horizontalDpi;
740            mVerticalDpi = verticalDpi;
741            mPackageName = null;
742            mLabelResId = 0;
743        }
744
745        /** @hide */
746        public Resolution(String id, String label, String packageName,
747                int horizontalDpi, int verticalDpi, int labelResId) {
748            mId = id;
749            mPackageName = packageName;
750            mLabelResId = labelResId;
751            mHorizontalDpi = horizontalDpi;
752            mVerticalDpi = verticalDpi;
753            mLabel = label;
754        }
755
756        /**
757         * Gets the unique resolution id.
758         *
759         * @return The unique resolution id.
760         */
761        public String getId() {
762            return mId;
763        }
764
765        /**
766         * Gets the resolution human readable label.
767         *
768         * @param packageManager The package manager for loading the label.
769         * @return The human readable label.
770         */
771        public String getLabel(PackageManager packageManager) {
772            if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
773                try {
774                    return packageManager.getResourcesForApplication(
775                            mPackageName).getString(mLabelResId);
776                } catch (NotFoundException nfe) {
777                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
778                            + " from package " + mPackageName);
779                } catch (NameNotFoundException nnfee) {
780                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
781                            + " from package " + mPackageName);
782                }
783            }
784            return mLabel;
785        }
786
787        /**
788         * Gets the vertical resolution in dpi.
789         *
790         * @return The horizontal resolution.
791         */
792        public int getHorizontalDpi() {
793            return mHorizontalDpi;
794        }
795
796        /**
797         * Gets the vertical resolution in dpi.
798         *
799         * @return The vertical resolution.
800         */
801        public int getVerticalDpi() {
802            return mVerticalDpi;
803        }
804
805        void writeToParcel(Parcel parcel) {
806            parcel.writeString(mId);
807            parcel.writeString(mLabel);
808            parcel.writeString(mPackageName);
809            parcel.writeInt(mHorizontalDpi);
810            parcel.writeInt(mVerticalDpi);
811            parcel.writeInt(mLabelResId);
812        }
813
814        static Resolution createFromParcel(Parcel parcel) {
815            return new Resolution(
816                    parcel.readString(),
817                    parcel.readString(),
818                    parcel.readString(),
819                    parcel.readInt(),
820                    parcel.readInt(),
821                    parcel.readInt());
822        }
823
824        @Override
825        public int hashCode() {
826            final int prime = 31;
827            int result = 1;
828            result = prime * result + ((mId == null) ? 0 : mId.hashCode());
829            result = prime * result + mHorizontalDpi;
830            result = prime * result + mVerticalDpi;
831            return result;
832        }
833
834        @Override
835        public boolean equals(Object obj) {
836            if (this == obj) {
837                return true;
838            }
839            if (obj == null) {
840                return false;
841            }
842            if (getClass() != obj.getClass()) {
843                return false;
844            }
845            Resolution other = (Resolution) obj;
846            if (!TextUtils.equals(mId, other.mId)) {
847                return false;
848            }
849            if (mHorizontalDpi != other.mHorizontalDpi) {
850                return false;
851            }
852            if (mVerticalDpi != other.mVerticalDpi) {
853                return false;
854            }
855            return true;
856        }
857
858        @Override
859        public String toString() {
860            StringBuilder builder = new StringBuilder();
861            builder.append("Resolution{");
862            builder.append("id: ").append(mId);
863            builder.append(", label: ").append(mLabel);
864            builder.append(", packageName: ").append(mPackageName);
865            builder.append(", horizontalDpi: ").append(mHorizontalDpi);
866            builder.append(", verticalDpi: ").append(mVerticalDpi);
867            builder.append(", labelResId: ").append(mLabelResId);
868            builder.append("}");
869            return builder.toString();
870        }
871    }
872
873    /**
874     * This class specifies content margins.
875     */
876    public static final class Margins {
877        public static final Margins NO_MARGINS = new Margins(0,  0,  0,  0);
878
879        private final int mLeftMils;
880        private final int mTopMils;
881        private final int mRightMils;
882        private final int mBottomMils;
883
884        /**
885         * Creates a new instance.
886         *
887         * @param leftMils The left margin in mils (thousands of an inch).
888         * @param topMils The top margin in mils (thousands of an inch).
889         * @param rightMils The right margin in mils (thousands of an inch).
890         * @param bottomMils The bottom margin in mils (thousands of an inch).
891         */
892        public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
893            if (leftMils > rightMils) {
894                throw new IllegalArgumentException("leftMils cannot be less than rightMils.");
895            }
896            if (topMils > bottomMils) {
897                throw new IllegalArgumentException("topMils cannot be less than bottomMils.");
898            }
899            mTopMils = topMils;
900            mLeftMils = leftMils;
901            mRightMils = rightMils;
902            mBottomMils = bottomMils;
903        }
904
905        /**
906         * Gets the left margin in mils (thousands of an inch).
907         *
908         * @return The left margin.
909         */
910        public int getLeftMils() {
911            return mLeftMils;
912        }
913
914        /**
915         * Gets the top margin in mils (thousands of an inch).
916         *
917         * @return The top margin.
918         */
919        public int getTopMils() {
920            return mTopMils;
921        }
922
923        /**
924         * Gets the right margin in mils (thousands of an inch).
925         *
926         * @return The right margin.
927         */
928        public int getRightMils() {
929            return mRightMils;
930        }
931
932        /**
933         * Gets the bottom margin in mils (thousands of an inch).
934         *
935         * @return The bottom margin.
936         */
937        public int getBottomMils() {
938            return mBottomMils;
939        }
940
941        void writeToParcel(Parcel parcel) {
942            parcel.writeInt(mLeftMils);
943            parcel.writeInt(mTopMils);
944            parcel.writeInt(mRightMils);
945            parcel.writeInt(mBottomMils);
946        }
947
948        static Margins createFromParcel(Parcel parcel) {
949            return new Margins(
950                    parcel.readInt(),
951                    parcel.readInt(),
952                    parcel.readInt(),
953                    parcel.readInt());
954        }
955
956        @Override
957        public int hashCode() {
958            final int prime = 31;
959            int result = 1;
960            result = prime * result + mBottomMils;
961            result = prime * result + mLeftMils;
962            result = prime * result + mRightMils;
963            result = prime * result + mTopMils;
964            return result;
965        }
966
967        @Override
968        public boolean equals(Object obj) {
969            if (this == obj) {
970                return true;
971            }
972            if (obj == null) {
973                return false;
974            }
975            if (getClass() != obj.getClass()) {
976                return false;
977            }
978            Margins other = (Margins) obj;
979            if (mBottomMils != other.mBottomMils) {
980                return false;
981            }
982            if (mLeftMils != other.mLeftMils) {
983                return false;
984            }
985            if (mRightMils != other.mRightMils) {
986                return false;
987            }
988            if (mTopMils != other.mTopMils) {
989                return false;
990            }
991            return true;
992        }
993
994        @Override
995        public String toString() {
996            StringBuilder builder = new StringBuilder();
997            builder.append("Margins{");
998            builder.append("leftMils: ").append(mLeftMils);
999            builder.append(", topMils: ").append(mTopMils);
1000            builder.append(", rightMils: ").append(mRightMils);
1001            builder.append(", bottomMils: ").append(mBottomMils);
1002            builder.append("}");
1003            return builder.toString();
1004        }
1005    }
1006
1007    static String colorModeToString(int colorMode) {
1008        switch (colorMode) {
1009            case COLOR_MODE_MONOCHROME: {
1010                return "COLOR_MODE_MONOCHROME";
1011            }
1012            case COLOR_MODE_COLOR: {
1013                return "COLOR_MODE_COLOR";
1014            }
1015            default:
1016                return "COLOR_MODE_UNKNOWN";
1017        }
1018    }
1019
1020    static void enforceValidColorMode(int colorMode) {
1021        if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) {
1022            throw new IllegalArgumentException("invalid color mode: " + colorMode);
1023        }
1024    }
1025
1026    /**
1027     * Builder for creating {@link PrintAttributes}.
1028     */
1029    public static final class Builder {
1030        private final PrintAttributes mAttributes = new PrintAttributes();
1031
1032        /**
1033         * Sets the media size.
1034         *
1035         * @param mediaSize The media size.
1036         * @return This builder.
1037         */
1038        public Builder setMediaSize(MediaSize mediaSize) {
1039            mAttributes.setMediaSize(mediaSize);
1040            return this;
1041        }
1042
1043        /**
1044         * Sets the resolution.
1045         *
1046         * @param resolution The resolution.
1047         * @return This builder.
1048         */
1049        public Builder setResolution(Resolution resolution) {
1050            mAttributes.setResolution(resolution);
1051            return this;
1052        }
1053
1054        /**
1055         * Sets the margins.
1056         *
1057         * @param margins The margins.
1058         * @return This builder.
1059         */
1060        public Builder setMargins(Margins margins) {
1061            mAttributes.setMargins(margins);
1062            return this;
1063        }
1064
1065        /**
1066         * Sets the color mode.
1067         *
1068         * @param colorMode A valid color mode or zero.
1069         * @return This builder.
1070         *
1071         * @see PrintAttributes#COLOR_MODE_MONOCHROME
1072         * @see PrintAttributes#COLOR_MODE_COLOR
1073         */
1074        public Builder setColorMode(int colorMode) {
1075            if (Integer.bitCount(colorMode) > 1) {
1076                throw new IllegalArgumentException("can specify at most one colorMode bit.");
1077            }
1078            mAttributes.setColorMode(colorMode);
1079            return this;
1080        }
1081
1082        /**
1083         * Creates a new {@link PrintAttributes} instance.
1084         *
1085         * @return The new instance.
1086         */
1087        public PrintAttributes create() {
1088            return mAttributes;
1089        }
1090    }
1091
1092    public static final Parcelable.Creator<PrintAttributes> CREATOR =
1093            new Creator<PrintAttributes>() {
1094        @Override
1095        public PrintAttributes createFromParcel(Parcel parcel) {
1096            return new PrintAttributes(parcel);
1097        }
1098
1099        @Override
1100        public PrintAttributes[] newArray(int size) {
1101            return new PrintAttributes[size];
1102        }
1103    };
1104}
1105