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