PrintAttributes.java revision a36285f3f2f74b1d2d5d0336ffe519ab9f6e062a
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         * @hide
417         */
418        public MediaSize(String id, String packageName, int labelResId,
419                int widthMils, int heightMils) {
420            if (TextUtils.isEmpty(id)) {
421                throw new IllegalArgumentException("id cannot be empty.");
422            }
423            if (TextUtils.isEmpty(packageName)) {
424                throw new IllegalArgumentException("packageName cannot be empty.");
425            }
426            if (labelResId <= 0) {
427                throw new IllegalArgumentException("labelResId must be greater than zero.");
428            }
429            if (widthMils <= 0) {
430                throw new IllegalArgumentException("widthMils "
431                        + "cannot be less than or equal to zero.");
432            }
433            if (heightMils <= 0) {
434                throw new IllegalArgumentException("heightMils "
435                       + "cannot be less than or euqual to zero.");
436            }
437            mPackageName = packageName;
438            mId = id;
439            mLabelResId = labelResId;
440            mWidthMils = widthMils;
441            mHeightMils = heightMils;
442            mLabel = null;
443        }
444
445        /**
446         * Creates a new instance.
447         *
448         * @param id The unique media size id.
449         * @param label The <strong>internationalized</strong> human readable label.
450         * @param widthMils The width in mils (thousands of an inch).
451         * @param heightMils The height in mils (thousands of an inch).
452         *
453         * @throws IllegalArgumentException If the id is empty.
454         * @throws IllegalArgumentException If the label is empty.
455         * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
456         * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
457         */
458        public MediaSize(String id, String label, int widthMils, int heightMils) {
459            if (TextUtils.isEmpty(id)) {
460                throw new IllegalArgumentException("id cannot be empty.");
461            }
462            if (TextUtils.isEmpty(label)) {
463                throw new IllegalArgumentException("label cannot be empty.");
464            }
465            if (widthMils <= 0) {
466                throw new IllegalArgumentException("widthMils "
467                        + "cannot be less than or equal to zero.");
468            }
469            if (heightMils <= 0) {
470                throw new IllegalArgumentException("heightMils "
471                       + "cannot be less than or euqual to zero.");
472            }
473            mId = id;
474            mLabel = label;
475            mWidthMils = widthMils;
476            mHeightMils = heightMils;
477            mLabelResId = 0;
478            mPackageName = null;
479        }
480
481        /** @hide */
482        public MediaSize(String id, String label, String packageName,
483                int widthMils, int heightMils, int labelResId) {
484            mPackageName = packageName;
485            mId = id;
486            mLabelResId = labelResId;
487            mWidthMils = widthMils;
488            mHeightMils = heightMils;
489            mLabel = label;
490        }
491
492        /**
493         * Gets the unique media size id.
494         *
495         * @return The unique media size id.
496         */
497        public String getId() {
498            return mId;
499        }
500
501        /**
502         * Gets the human readable media size label.
503         *
504         * @param packageManager The package manager for loading the label.
505         * @return The human readable label.
506         */
507        public String getLabel(PackageManager packageManager) {
508            if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
509                try {
510                    return packageManager.getResourcesForApplication(
511                            mPackageName).getString(mLabelResId);
512                } catch (NotFoundException nfe) {
513                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
514                            + " from package " + mPackageName);
515                } catch (NameNotFoundException nnfee) {
516                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
517                            + " from package " + mPackageName);
518                }
519            }
520            return mLabel;
521        }
522
523        /**
524         * Gets the media width in mils (thousands of an inch).
525         *
526         * @return The media width.
527         */
528        public int getWidthMils() {
529            return mWidthMils;
530        }
531
532        /**
533         * Gets the media height in mils (thousands of an inch).
534         *
535         * @return The media height.
536         */
537        public int getHeightMils() {
538            return mHeightMils;
539        }
540
541        /**
542         * Gets whether this media size is in portrait which is the
543         * height is greater or equal to the width.
544         *
545         * @return True if the media size is in portrait, false if
546         * it is in landscape.
547         */
548        public boolean isPortrait() {
549            return mHeightMils >= mWidthMils;
550        }
551
552        /**
553         * Returns a new media size in a portrait orientation
554         * which is the height is the greater dimension.
555         *
556         * @return New instance in landscape orientation.
557         */
558        public MediaSize asPortrait() {
559            return new MediaSize(mId, mLabel, mPackageName,
560                    Math.min(mWidthMils, mHeightMils),
561                    Math.max(mWidthMils, mHeightMils),
562                    mLabelResId);
563        }
564
565        /**
566         * Returns a new media size in a landscape orientation
567         * which is the height is the lesser dimension.
568         *
569         * @return New instance in landscape orientation.
570         */
571        public MediaSize asLandscape() {
572            return new MediaSize(mId, mLabel, mPackageName,
573                    Math.max(mWidthMils, mHeightMils),
574                    Math.min(mWidthMils, mHeightMils),
575                    mLabelResId);
576        }
577
578        void writeToParcel(Parcel parcel) {
579            parcel.writeString(mId);
580            parcel.writeString(mLabel);
581            parcel.writeString(mPackageName);
582            parcel.writeInt(mWidthMils);
583            parcel.writeInt(mHeightMils);
584            parcel.writeInt(mLabelResId);
585        }
586
587        static MediaSize createFromParcel(Parcel parcel) {
588            return new MediaSize(
589                    parcel.readString(),
590                    parcel.readString(),
591                    parcel.readString(),
592                    parcel.readInt(),
593                    parcel.readInt(),
594                    parcel.readInt());
595        }
596
597        @Override
598        public int hashCode() {
599            final int prime = 31;
600            int result = 1;
601            result = prime * result + mWidthMils;
602            result = prime * result + mHeightMils;
603            return result;
604        }
605
606        @Override
607        public boolean equals(Object obj) {
608            if (this == obj) {
609                return true;
610            }
611            if (obj == null) {
612                return false;
613            }
614            if (getClass() != obj.getClass()) {
615                return false;
616            }
617            MediaSize other = (MediaSize) obj;
618            if (mWidthMils != other.mWidthMils) {
619                return false;
620            }
621            if (mHeightMils != other.mHeightMils) {
622                return false;
623            }
624            return true;
625        }
626
627        @Override
628        public String toString() {
629            StringBuilder builder = new StringBuilder();
630            builder.append("MediaSize{");
631            builder.append("id: ").append(mId);
632            builder.append(", label: ").append(mLabel);
633            builder.append(", packageName: ").append(mPackageName);
634            builder.append(", heightMils: ").append(mHeightMils);
635            builder.append(", widthMils: ").append(mWidthMils);
636            builder.append(", labelResId: ").append(mLabelResId);
637            builder.append("}");
638            return builder.toString();
639        }
640    }
641
642    /**
643     * This class specifies a supported resolution in dpi (dots per inch).
644     */
645    public static final class Resolution {
646        private static final String LOG_TAG = "Resolution";
647
648        private final String mId;
649        /**@hide */
650        public final String mLabel;
651        /**@hide */
652        public final String mPackageName;
653        /**@hide */
654        public final int mLabelResId;
655        private final int mHorizontalDpi;
656        private final int mVerticalDpi;
657
658        /**
659         * Creates a new instance. This is the preferred constructor since
660         * it enables the resolution label to be shown in a localized fashion
661         * on a locale change.
662         *
663         * @param id The unique resolution id.
664         * @param packageName The name of the creating package.
665         * @param labelResId The resource id of a human readable label.
666         * @param horizontalDpi The horizontal resolution in dpi.
667         * @param verticalDpi The vertical resolution in dpi.
668         *
669         * @throws IllegalArgumentException If the id is empty.
670         * @throws IllegalArgumentException If the label is empty.
671         * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
672         * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
673         *
674         * @hide
675         */
676        public Resolution(String id, String packageName, int labelResId,
677                int horizontalDpi, int verticalDpi) {
678            if (TextUtils.isEmpty(id)) {
679                throw new IllegalArgumentException("id cannot be empty.");
680            }
681            if (TextUtils.isEmpty(packageName)) {
682                throw new IllegalArgumentException("packageName cannot be empty.");
683            }
684            if (labelResId <= 0) {
685                throw new IllegalArgumentException("labelResId must be greater than zero.");
686            }
687            if (horizontalDpi <= 0) {
688                throw new IllegalArgumentException("horizontalDpi "
689                        + "cannot be less than or equal to zero.");
690            }
691            if (verticalDpi <= 0) {
692                throw new IllegalArgumentException("verticalDpi"
693                       + " cannot be less than or equal to zero.");
694            }
695            mId = id;
696            mPackageName = packageName;
697            mLabelResId = labelResId;
698            mHorizontalDpi = horizontalDpi;
699            mVerticalDpi = verticalDpi;
700            mLabel = null;
701        }
702
703        /**
704         * Creates a new instance.
705         *
706         * @param id The unique resolution id.
707         * @param label The <strong>internationalized</strong> human readable label.
708         * @param horizontalDpi The horizontal resolution in dpi.
709         * @param verticalDpi The vertical resolution in dpi.
710         *
711         * @throws IllegalArgumentException If the id is empty.
712         * @throws IllegalArgumentException If the label is empty.
713         * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
714         * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
715         */
716        public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
717            if (TextUtils.isEmpty(id)) {
718                throw new IllegalArgumentException("id cannot be empty.");
719            }
720            if (TextUtils.isEmpty(label)) {
721                throw new IllegalArgumentException("label cannot be empty.");
722            }
723            if (horizontalDpi <= 0) {
724                throw new IllegalArgumentException("horizontalDpi "
725                        + "cannot be less than or equal to zero.");
726            }
727            if (verticalDpi <= 0) {
728                throw new IllegalArgumentException("verticalDpi"
729                       + " cannot be less than or equal to zero.");
730            }
731            mId = id;
732            mLabel = label;
733            mHorizontalDpi = horizontalDpi;
734            mVerticalDpi = verticalDpi;
735            mPackageName = null;
736            mLabelResId = 0;
737        }
738
739        /** @hide */
740        public Resolution(String id, String label, String packageName,
741                int horizontalDpi, int verticalDpi, int labelResId) {
742            mId = id;
743            mPackageName = packageName;
744            mLabelResId = labelResId;
745            mHorizontalDpi = horizontalDpi;
746            mVerticalDpi = verticalDpi;
747            mLabel = label;
748        }
749
750        /**
751         * Gets the unique resolution id.
752         *
753         * @return The unique resolution id.
754         */
755        public String getId() {
756            return mId;
757        }
758
759        /**
760         * Gets the resolution human readable label.
761         *
762         * @param packageManager The package manager for loading the label.
763         * @return The human readable label.
764         */
765        public String getLabel(PackageManager packageManager) {
766            if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
767                try {
768                    return packageManager.getResourcesForApplication(
769                            mPackageName).getString(mLabelResId);
770                } catch (NotFoundException nfe) {
771                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
772                            + " from package " + mPackageName);
773                } catch (NameNotFoundException nnfee) {
774                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
775                            + " from package " + mPackageName);
776                }
777            }
778            return mLabel;
779        }
780
781        /**
782         * Gets the vertical resolution in dpi.
783         *
784         * @return The horizontal resolution.
785         */
786        public int getHorizontalDpi() {
787            return mHorizontalDpi;
788        }
789
790        /**
791         * Gets the vertical resolution in dpi.
792         *
793         * @return The vertical resolution.
794         */
795        public int getVerticalDpi() {
796            return mVerticalDpi;
797        }
798
799        void writeToParcel(Parcel parcel) {
800            parcel.writeString(mId);
801            parcel.writeString(mLabel);
802            parcel.writeString(mPackageName);
803            parcel.writeInt(mHorizontalDpi);
804            parcel.writeInt(mVerticalDpi);
805            parcel.writeInt(mLabelResId);
806        }
807
808        static Resolution createFromParcel(Parcel parcel) {
809            return new Resolution(
810                    parcel.readString(),
811                    parcel.readString(),
812                    parcel.readString(),
813                    parcel.readInt(),
814                    parcel.readInt(),
815                    parcel.readInt());
816        }
817
818        @Override
819        public int hashCode() {
820            final int prime = 31;
821            int result = 1;
822            result = prime * result + mHorizontalDpi;
823            result = prime * result + mVerticalDpi;
824            return result;
825        }
826
827        @Override
828        public boolean equals(Object obj) {
829            if (this == obj) {
830                return true;
831            }
832            if (obj == null) {
833                return false;
834            }
835            if (getClass() != obj.getClass()) {
836                return false;
837            }
838            Resolution other = (Resolution) obj;
839            if (mHorizontalDpi != other.mHorizontalDpi) {
840                return false;
841            }
842            if (mVerticalDpi != other.mVerticalDpi) {
843                return false;
844            }
845            return true;
846        }
847
848        @Override
849        public String toString() {
850            StringBuilder builder = new StringBuilder();
851            builder.append("Resolution{");
852            builder.append("id: ").append(mId);
853            builder.append(", label: ").append(mLabel);
854            builder.append(", packageName: ").append(mPackageName);
855            builder.append(", horizontalDpi: ").append(mHorizontalDpi);
856            builder.append(", verticalDpi: ").append(mVerticalDpi);
857            builder.append(", labelResId: ").append(mLabelResId);
858            builder.append("}");
859            return builder.toString();
860        }
861    }
862
863    /**
864     * This class specifies content margins.
865     */
866    public static final class Margins {
867        public static final Margins NO_MARGINS = new Margins(0,  0,  0,  0);
868
869        private final int mLeftMils;
870        private final int mTopMils;
871        private final int mRightMils;
872        private final int mBottomMils;
873
874        /**
875         * Creates a new instance.
876         *
877         * @param leftMils The left margin in mils (thousands of an inch).
878         * @param topMils The top margin in mils (thousands of an inch).
879         * @param rightMils The right margin in mils (thousands of an inch).
880         * @param bottomMils The bottom margin in mils (thousands of an inch).
881         */
882        public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
883            if (leftMils > rightMils) {
884                throw new IllegalArgumentException("leftMils cannot be less than rightMils.");
885            }
886            if (topMils > bottomMils) {
887                throw new IllegalArgumentException("topMils cannot be less than bottomMils.");
888            }
889            mTopMils = topMils;
890            mLeftMils = leftMils;
891            mRightMils = rightMils;
892            mBottomMils = bottomMils;
893        }
894
895        /**
896         * Gets the left margin in mils (thousands of an inch).
897         *
898         * @return The left margin.
899         */
900        public int getLeftMils() {
901            return mLeftMils;
902        }
903
904        /**
905         * Gets the top margin in mils (thousands of an inch).
906         *
907         * @return The top margin.
908         */
909        public int getTopMils() {
910            return mTopMils;
911        }
912
913        /**
914         * Gets the right margin in mils (thousands of an inch).
915         *
916         * @return The right margin.
917         */
918        public int getRightMils() {
919            return mRightMils;
920        }
921
922        /**
923         * Gets the bottom margin in mils (thousands of an inch).
924         *
925         * @return The bottom margin.
926         */
927        public int getBottomMils() {
928            return mBottomMils;
929        }
930
931        void writeToParcel(Parcel parcel) {
932            parcel.writeInt(mLeftMils);
933            parcel.writeInt(mTopMils);
934            parcel.writeInt(mRightMils);
935            parcel.writeInt(mBottomMils);
936        }
937
938        static Margins createFromParcel(Parcel parcel) {
939            return new Margins(
940                    parcel.readInt(),
941                    parcel.readInt(),
942                    parcel.readInt(),
943                    parcel.readInt());
944        }
945
946        @Override
947        public int hashCode() {
948            final int prime = 31;
949            int result = 1;
950            result = prime * result + mBottomMils;
951            result = prime * result + mLeftMils;
952            result = prime * result + mRightMils;
953            result = prime * result + mTopMils;
954            return result;
955        }
956
957        @Override
958        public boolean equals(Object obj) {
959            if (this == obj) {
960                return true;
961            }
962            if (obj == null) {
963                return false;
964            }
965            if (getClass() != obj.getClass()) {
966                return false;
967            }
968            Margins other = (Margins) obj;
969            if (mBottomMils != other.mBottomMils) {
970                return false;
971            }
972            if (mLeftMils != other.mLeftMils) {
973                return false;
974            }
975            if (mRightMils != other.mRightMils) {
976                return false;
977            }
978            if (mTopMils != other.mTopMils) {
979                return false;
980            }
981            return true;
982        }
983
984        @Override
985        public String toString() {
986            StringBuilder builder = new StringBuilder();
987            builder.append("Margins{");
988            builder.append("leftMils: ").append(mLeftMils);
989            builder.append(", topMils: ").append(mTopMils);
990            builder.append(", rightMils: ").append(mRightMils);
991            builder.append(", bottomMils: ").append(mBottomMils);
992            builder.append("}");
993            return builder.toString();
994        }
995    }
996
997    static String colorModeToString(int colorMode) {
998        switch (colorMode) {
999            case COLOR_MODE_MONOCHROME: {
1000                return "COLOR_MODE_MONOCHROME";
1001            }
1002            case COLOR_MODE_COLOR: {
1003                return "COLOR_MODE_COLOR";
1004            }
1005            default:
1006                return "COLOR_MODE_UNKNOWN";
1007        }
1008    }
1009
1010    static void enforceValidColorMode(int colorMode) {
1011        if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) {
1012            throw new IllegalArgumentException("invalid color mode: " + colorMode);
1013        }
1014    }
1015
1016    /**
1017     * Builder for creating {@link PrintAttributes}.
1018     */
1019    public static final class Builder {
1020        private final PrintAttributes mAttributes = new PrintAttributes();
1021
1022        /**
1023         * Sets the media size.
1024         *
1025         * @param mediaSize The media size.
1026         * @return This builder.
1027         */
1028        public Builder setMediaSize(MediaSize mediaSize) {
1029            mAttributes.setMediaSize(mediaSize);
1030            return this;
1031        }
1032
1033        /**
1034         * Sets the resolution.
1035         *
1036         * @param resolution The resolution.
1037         * @return This builder.
1038         */
1039        public Builder setResolution(Resolution resolution) {
1040            mAttributes.setResolution(resolution);
1041            return this;
1042        }
1043
1044        /**
1045         * Sets the margins.
1046         *
1047         * @param margins The margins.
1048         * @return This builder.
1049         */
1050        public Builder setMargins(Margins margins) {
1051            mAttributes.setMargins(margins);
1052            return this;
1053        }
1054
1055        /**
1056         * Sets the color mode.
1057         *
1058         * @param colorMode A valid color mode or zero.
1059         * @return This builder.
1060         *
1061         * @see PrintAttributes#COLOR_MODE_MONOCHROME
1062         * @see PrintAttributes#COLOR_MODE_COLOR
1063         */
1064        public Builder setColorMode(int colorMode) {
1065            if (Integer.bitCount(colorMode) > 1) {
1066                throw new IllegalArgumentException("can specify at most one colorMode bit.");
1067            }
1068            mAttributes.setColorMode(colorMode);
1069            return this;
1070        }
1071
1072        /**
1073         * Creates a new {@link PrintAttributes} instance.
1074         *
1075         * @return The new instance.
1076         */
1077        public PrintAttributes create() {
1078            return mAttributes;
1079        }
1080    }
1081
1082    public static final Parcelable.Creator<PrintAttributes> CREATOR =
1083            new Creator<PrintAttributes>() {
1084        @Override
1085        public PrintAttributes createFromParcel(Parcel parcel) {
1086            return new PrintAttributes(parcel);
1087        }
1088
1089        @Override
1090        public PrintAttributes[] newArray(int size) {
1091            return new PrintAttributes[size];
1092        }
1093    };
1094}
1095