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