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