PrinterInfo.java revision 55b409a97cf6376399a0940313ea852368727d6f
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.print; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.print.PrintAttributes.Margins; 22import android.print.PrintAttributes.MediaSize; 23import android.print.PrintAttributes.Resolution; 24import android.print.PrintAttributes.Tray; 25import android.text.TextUtils; 26 27import java.util.ArrayList; 28import java.util.Arrays; 29import java.util.List; 30 31/** 32 * This class represents the description of a printer. A description 33 * contains the printer id, human readable name, status, and available 34 * options for various printer capabilities, such as media size, etc. 35 */ 36public final class PrinterInfo implements Parcelable { 37 /** 38 * Undefined default value. 39 * 40 * @hide 41 */ 42 public static final int DEFAULT_UNDEFINED = -1; 43 44 private static final int PROPERTY_MEDIA_SIZE = 0; 45 private static final int PROPERTY_RESOLUTION = 1; 46 private static final int PROPERTY_INPUT_TRAY = 2; 47 private static final int PROPERTY_OUTPUT_TRAY = 3; 48 private static final int PROPERTY_DUPLEX_MODE = 4; 49 private static final int PROPERTY_COLOR_MODE = 5; 50 private static final int PROPERTY_FITTING_MODE = 6; 51 private static final int PROPERTY_ORIENTATION = 7; 52 private static final int PROPERTY_COUNT = 8; 53 54 /** Printer status: the printer is ready to print. */ 55 public static final int STATUS_READY = 1; 56 57 private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0); 58 59 // TODO: Add printer status constants. 60 61 private PrinterId mId; 62 private CharSequence mLabel; 63 private int mStatus; 64 65 private Margins mMinMargins = DEFAULT_MARGINS; 66 private List<MediaSize> mMediaSizes; 67 private List<Resolution> mResolutions; 68 private List<Tray> mInputTrays; 69 private List<Tray> mOutputTrays; 70 71 private int mDuplexModes; 72 private int mColorModes; 73 private int mFittingModes; 74 private int mOrientations; 75 76 private final int[] mDefaults = new int[PROPERTY_COUNT]; 77 private Margins mDefaultMargins = DEFAULT_MARGINS; 78 79 /** 80 * @hide 81 */ 82 public PrinterInfo() { 83 Arrays.fill(mDefaults, DEFAULT_UNDEFINED); 84 } 85 86 private PrinterInfo(PrinterInfo prototype) { 87 copyFrom(prototype); 88 } 89 90 /** 91 * @hide 92 */ 93 public void copyFrom(PrinterInfo other) { 94 mId = other.mId; 95 mLabel = other.mLabel; 96 mStatus = other.mStatus; 97 98 mMinMargins = other.mMinMargins; 99 if (other.mMediaSizes != null) { 100 if (mMediaSizes != null) { 101 mMediaSizes.clear(); 102 mMediaSizes.addAll(other.mMediaSizes); 103 } else { 104 mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes); 105 } 106 } else { 107 mMediaSizes = null; 108 } 109 110 if (other.mResolutions != null) { 111 if (mResolutions != null) { 112 mResolutions.clear(); 113 mResolutions.addAll(other.mResolutions); 114 } else { 115 mResolutions = new ArrayList<Resolution>(other.mResolutions); 116 } 117 } else { 118 mResolutions = null; 119 } 120 121 if (other.mInputTrays != null) { 122 if (mInputTrays != null) { 123 mInputTrays.clear(); 124 mInputTrays.addAll(other.mInputTrays); 125 } else { 126 mInputTrays = new ArrayList<Tray>(other.mInputTrays); 127 } 128 } else { 129 mInputTrays = null; 130 } 131 132 if (other.mOutputTrays != null) { 133 if (mOutputTrays != null) { 134 mOutputTrays.clear(); 135 mOutputTrays.addAll(other.mOutputTrays); 136 } else { 137 mOutputTrays = new ArrayList<Tray>(other.mOutputTrays); 138 } 139 } else { 140 mOutputTrays = null; 141 } 142 143 mDuplexModes = other.mDuplexModes; 144 mColorModes = other.mColorModes; 145 mFittingModes = other.mFittingModes; 146 mOrientations = other.mOrientations; 147 148 final int defaultCount = other.mDefaults.length; 149 for (int i = 0; i < defaultCount; i++) { 150 mDefaults[i] = other.mDefaults[i]; 151 } 152 mDefaultMargins = other.mDefaultMargins; 153 } 154 155 /** 156 * Get the globally unique printer id. 157 * 158 * @return The printer id. 159 */ 160 public PrinterId getId() { 161 return mId; 162 } 163 164 /** 165 * Gets the human readable printer label. 166 * 167 * @return The human readable label. 168 */ 169 public CharSequence getLabel() { 170 return mLabel; 171 } 172 173 /** 174 * Gets the status of the printer. 175 * 176 * @return The status. 177 */ 178 public int getStatus() { 179 return mStatus; 180 } 181 182 /** 183 * Gets the supported media sizes. 184 * 185 * @return The supported media sizes. 186 */ 187 public List<MediaSize> getMediaSizes() { 188 return mMediaSizes; 189 } 190 191 /** 192 * Gets the supported resolutions. 193 * 194 * @return The supported resolutions. 195 */ 196 public List<Resolution> getResolutions() { 197 return mResolutions; 198 } 199 200 /** 201 * Gets the minimal supported margins. 202 * 203 * @return The minimal margins. 204 */ 205 public Margins getMinMargins() { 206 return mMinMargins; 207 } 208 209 /** 210 * Gets the available input trays. 211 * 212 * @return The input trays. 213 */ 214 public List<Tray> getInputTrays() { 215 return mInputTrays; 216 } 217 218 /** 219 * Gets the available output trays. 220 * 221 * @return The output trays. 222 */ 223 public List<Tray> getOutputTrays() { 224 return mOutputTrays; 225 } 226 227 /** 228 * Gets the supported duplex modes. 229 * 230 * @return The duplex modes. 231 * 232 * @see PrintAttributes#DUPLEX_MODE_NONE 233 * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE 234 * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE 235 */ 236 public int getDuplexModes() { 237 return mDuplexModes; 238 } 239 240 /** 241 * Gets the supported color modes. 242 * 243 * @return The color modes. 244 * 245 * @see PrintAttributes#COLOR_MODE_COLOR 246 * @see PrintAttributes#COLOR_MODE_MONOCHROME 247 */ 248 public int getColorModes() { 249 return mColorModes; 250 } 251 252 /** 253 * Gets the supported fitting modes. 254 * 255 * @return The fitting modes. 256 * 257 * @see PrintAttributes#FITTING_MODE_NONE 258 * @see PrintAttributes#FITTING_MODE_FIT_TO_PAGE 259 */ 260 public int getFittingModes() { 261 return mFittingModes; 262 } 263 264 /** 265 * Gets the supported orientations. 266 * 267 * @return The orientations. 268 * 269 * @see PrintAttributes#ORIENTATION_PORTRAIT 270 * @see PrintAttributes#ORIENTATION_LANDSCAPE 271 */ 272 public int getOrientations() { 273 return mOrientations; 274 } 275 276 /** 277 * Gets the default print attributes. 278 * 279 * @param outAttributes The attributes to populated. 280 */ 281 public void getDefaults(PrintAttributes outAttributes) { 282 outAttributes.clear(); 283 284 outAttributes.setMargins(mDefaultMargins); 285 286 final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE]; 287 if (mediaSizeIndex >= 0) { 288 outAttributes.setMediaSize(mMediaSizes.get(mediaSizeIndex)); 289 } 290 291 final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION]; 292 if (resolutionIndex >= 0) { 293 outAttributes.setResolution(mResolutions.get(resolutionIndex)); 294 } 295 296 final int inputTrayIndex = mDefaults[PROPERTY_INPUT_TRAY]; 297 if (inputTrayIndex >= 0) { 298 outAttributes.setInputTray(mInputTrays.get(inputTrayIndex)); 299 } 300 301 final int outputTrayIndex = mDefaults[PROPERTY_OUTPUT_TRAY]; 302 if (outputTrayIndex >= 0) { 303 outAttributes.setOutputTray(mOutputTrays.get(outputTrayIndex)); 304 } 305 306 final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE]; 307 if (duplexMode > 0) { 308 outAttributes.setDuplexMode(duplexMode); 309 } 310 311 final int colorMode = mDefaults[PROPERTY_COLOR_MODE]; 312 if (colorMode > 0) { 313 outAttributes.setColorMode(mColorModes & colorMode); 314 } 315 316 final int fittingMode = mDefaults[PROPERTY_FITTING_MODE]; 317 if (fittingMode > 0) { 318 outAttributes.setFittingMode(fittingMode); 319 } 320 321 final int orientation = mDefaults[PROPERTY_ORIENTATION]; 322 if (orientation > 0) { 323 outAttributes.setOrientation(orientation); 324 } 325 } 326 327 /** 328 * Gets whether this printer info is fully-populated, i.e. whether 329 * all required attributes are specified. See the {@link Builder} 330 * documentation for which attributes are required. 331 * 332 * @return Whether this info has all required attributes. 333 */ 334 public boolean hasAllRequiredAttributes() { 335 return (mMediaSizes != null && !mMediaSizes.isEmpty() 336 && mResolutions != null && !mResolutions.isEmpty() 337 && mColorModes != 0 || mOrientations != 0 338 && mDefaults[PROPERTY_MEDIA_SIZE] != DEFAULT_UNDEFINED 339 && mDefaults[PROPERTY_RESOLUTION] != DEFAULT_UNDEFINED 340 && mDefaults[PROPERTY_COLOR_MODE] != DEFAULT_UNDEFINED 341 && mDefaults[PROPERTY_ORIENTATION] != DEFAULT_UNDEFINED); 342 } 343 344 private PrinterInfo(Parcel parcel) { 345 mId = parcel.readParcelable(null); 346 mLabel = parcel.readCharSequence(); 347 mStatus = parcel.readInt(); 348 349 mMinMargins = readMargins(parcel); 350 readMediaSizes(parcel); 351 readResolutions(parcel); 352 mInputTrays = readInputTrays(parcel); 353 mOutputTrays = readOutputTrays(parcel); 354 355 mColorModes = parcel.readInt(); 356 mDuplexModes = parcel.readInt(); 357 mFittingModes = parcel.readInt(); 358 mOrientations = parcel.readInt(); 359 360 readDefaults(parcel); 361 mDefaultMargins = readMargins(parcel); 362 } 363 364 @Override 365 public int describeContents() { 366 return 0; 367 } 368 369 @Override 370 public void writeToParcel(Parcel parcel, int flags) { 371 parcel.writeParcelable(mId, flags); 372 parcel.writeCharSequence(mLabel); 373 parcel.writeInt(mStatus); 374 375 writeMargins(mMinMargins, parcel); 376 writeMediaSizes(parcel); 377 writeResolutions(parcel); 378 writeInputTrays(parcel); 379 writeOutputTrays(parcel); 380 381 parcel.writeInt(mColorModes); 382 parcel.writeInt(mDuplexModes); 383 parcel.writeInt(mFittingModes); 384 parcel.writeInt(mOrientations); 385 386 writeDefaults(parcel); 387 writeMargins(mDefaultMargins, parcel); 388 } 389 390 @Override 391 public int hashCode() { 392 final int prime = 31; 393 int result = 1; 394 result = prime * result + ((mId == null) ? 0 : mId.hashCode()); 395 result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode()); 396 result = prime * result + mStatus; 397 result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode()); 398 result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode()); 399 result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode()); 400 result = prime * result + ((mInputTrays == null) ? 0 : mInputTrays.hashCode()); 401 result = prime * result + ((mOutputTrays == null) ? 0 : mOutputTrays.hashCode()); 402 result = prime * result + mDuplexModes; 403 result = prime * result + mColorModes; 404 result = prime * result + mFittingModes; 405 result = prime * result + mOrientations; 406 result = prime * result + Arrays.hashCode(mDefaults); 407 result = prime * result + ((mDefaultMargins == null) ? 0 : mDefaultMargins.hashCode()); 408 return result; 409 } 410 411 @Override 412 public boolean equals(Object obj) { 413 if (this == obj) { 414 return true; 415 } 416 if (obj == null) { 417 return false; 418 } 419 if (getClass() != obj.getClass()) { 420 return false; 421 } 422 PrinterInfo other = (PrinterInfo) obj; 423 if (mId == null) { 424 if (other.mId != null) { 425 return false; 426 } 427 } else if (!mId.equals(other.mId)) { 428 return false; 429 } 430 if (!TextUtils.equals(mLabel, other.mLabel)) { 431 return false; 432 } 433 if (mStatus != other.mStatus) { 434 return false; 435 } 436 if (mMinMargins == null) { 437 if (other.mMinMargins != null) { 438 return false; 439 } 440 } else if (!mMinMargins.equals(other.mMinMargins)) { 441 return false; 442 } 443 if (mMediaSizes == null) { 444 if (other.mMediaSizes != null) { 445 return false; 446 } 447 } else if (!mMediaSizes.equals(other.mMediaSizes)) { 448 return false; 449 } 450 if (mResolutions == null) { 451 if (other.mResolutions != null) { 452 return false; 453 } 454 } else if (!mResolutions.equals(other.mResolutions)) { 455 return false; 456 } 457 if (mInputTrays == null) { 458 if (other.mInputTrays != null) { 459 return false; 460 } 461 } else if (!mInputTrays.equals(other.mInputTrays)) { 462 return false; 463 } 464 if (mOutputTrays == null) { 465 if (other.mOutputTrays != null) { 466 return false; 467 } 468 } else if (!mOutputTrays.equals(other.mOutputTrays)) { 469 return false; 470 } 471 if (mDuplexModes != other.mDuplexModes) { 472 return false; 473 } 474 if (mColorModes != other.mColorModes) { 475 return false; 476 } 477 if (mFittingModes != other.mFittingModes) { 478 return false; 479 } 480 if (mOrientations != other.mOrientations) { 481 return false; 482 } 483 if (!Arrays.equals(mDefaults, other.mDefaults)) { 484 return false; 485 } 486 if (mDefaultMargins == null) { 487 if (other.mDefaultMargins != null) { 488 return false; 489 } 490 } else if (!mDefaultMargins.equals(other.mDefaultMargins)) { 491 return false; 492 } 493 return true; 494 } 495 496 @Override 497 public String toString() { 498 StringBuilder builder = new StringBuilder(); 499 builder.append("PrinterInfo{"); 500 builder.append(mId).append(", \""); 501 builder.append(mLabel); 502 builder.append("\"}"); 503 return builder.toString(); 504 } 505 506 private void writeMediaSizes(Parcel parcel) { 507 if (mMediaSizes == null) { 508 parcel.writeInt(0); 509 return; 510 } 511 final int mediaSizeCount = mMediaSizes.size(); 512 parcel.writeInt(mediaSizeCount); 513 for (int i = 0; i < mediaSizeCount; i++) { 514 mMediaSizes.get(i).writeToParcel(parcel); 515 } 516 } 517 518 private void readMediaSizes(Parcel parcel) { 519 final int mediaSizeCount = parcel.readInt(); 520 if (mediaSizeCount > 0 && mMediaSizes == null) { 521 mMediaSizes = new ArrayList<MediaSize>(); 522 } 523 for (int i = 0; i < mediaSizeCount; i++) { 524 mMediaSizes.add(MediaSize.createFromParcel(parcel)); 525 } 526 } 527 528 private void writeResolutions(Parcel parcel) { 529 if (mResolutions == null) { 530 parcel.writeInt(0); 531 return; 532 } 533 final int resolutionCount = mResolutions.size(); 534 parcel.writeInt(resolutionCount); 535 for (int i = 0; i < resolutionCount; i++) { 536 mResolutions.get(i).writeToParcel(parcel); 537 } 538 } 539 540 private void readResolutions(Parcel parcel) { 541 final int resolutionCount = parcel.readInt(); 542 if (resolutionCount > 0 && mResolutions == null) { 543 mResolutions = new ArrayList<Resolution>(); 544 } 545 for (int i = 0; i < resolutionCount; i++) { 546 mResolutions.add(Resolution.createFromParcel(parcel)); 547 } 548 } 549 550 private void writeMargins(Margins margins, Parcel parcel) { 551 if (margins == null) { 552 parcel.writeInt(0); 553 } else { 554 parcel.writeInt(1); 555 margins.writeToParcel(parcel); 556 } 557 } 558 559 private Margins readMargins(Parcel parcel) { 560 return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null; 561 } 562 563 private void writeInputTrays(Parcel parcel) { 564 if (mInputTrays == null) { 565 parcel.writeInt(0); 566 return; 567 } 568 final int inputTrayCount = mInputTrays.size(); 569 parcel.writeInt(inputTrayCount); 570 for (int i = 0; i < inputTrayCount; i++) { 571 mInputTrays.get(i).writeToParcel(parcel); 572 } 573 } 574 575 private List<Tray> readInputTrays(Parcel parcel) { 576 final int inputTrayCount = parcel.readInt(); 577 if (inputTrayCount <= 0) { 578 return null; 579 } 580 List<Tray> inputTrays = new ArrayList<Tray>(inputTrayCount); 581 for (int i = 0; i < inputTrayCount; i++) { 582 inputTrays.add(Tray.createFromParcel(parcel)); 583 } 584 return inputTrays; 585 } 586 587 private void writeOutputTrays(Parcel parcel) { 588 if (mOutputTrays == null) { 589 parcel.writeInt(0); 590 return; 591 } 592 final int outputTrayCount = mOutputTrays.size(); 593 parcel.writeInt(outputTrayCount); 594 for (int i = 0; i < outputTrayCount; i++) { 595 mOutputTrays.get(i).writeToParcel(parcel); 596 } 597 } 598 599 private List<Tray> readOutputTrays(Parcel parcel) { 600 final int outputTrayCount = parcel.readInt(); 601 if (outputTrayCount <= 0) { 602 return null; 603 } 604 List<Tray> outputTrays = new ArrayList<Tray>(outputTrayCount); 605 for (int i = 0; i < outputTrayCount; i++) { 606 outputTrays.add(Tray.createFromParcel(parcel)); 607 } 608 return outputTrays; 609 } 610 611 private void readDefaults(Parcel parcel) { 612 final int defaultCount = parcel.readInt(); 613 for (int i = 0; i < defaultCount; i++) { 614 mDefaults[i] = parcel.readInt(); 615 } 616 } 617 618 private void writeDefaults(Parcel parcel) { 619 final int defaultCount = mDefaults.length; 620 parcel.writeInt(defaultCount); 621 for (int i = 0; i < defaultCount; i++) { 622 parcel.writeInt(mDefaults[i]); 623 } 624 } 625 626 /** 627 * Builder for creating of a {@link PrinterInfo}. This class is responsible 628 * to enforce that all required attributes have at least one default value. 629 * In other words, this class creates only well-formed {@link PrinterInfo}s. 630 * <p> 631 * Look at the individual methods for a reference whether a property is 632 * required or if it is optional. 633 * </p> 634 */ 635 public static final class Builder { 636 private final PrinterInfo mPrototype; 637 638 /** 639 * Creates a new instance. 640 * 641 * @param printerId The printer id. Cannot be null. 642 * @param label The human readable printer label. Cannot be null or empty. 643 * 644 * @throws IllegalArgumentException If the printer id is null. 645 * @throws IllegalArgumentException If the label is empty. 646 */ 647 public Builder(PrinterId printerId, CharSequence label) { 648 if (printerId == null) { 649 throw new IllegalArgumentException("printerId cannot be null."); 650 } 651 if (TextUtils.isEmpty(label)) { 652 throw new IllegalArgumentException("label cannot be empty."); 653 } 654 mPrototype = new PrinterInfo(); 655 mPrototype.mLabel = label; 656 mPrototype.mId = printerId; 657 } 658 659 /** 660 * Sets the printer status. 661 * <p> 662 * <strong>Required:</strong> Yes 663 * </p> 664 * 665 * @param status The status. 666 * @return This builder. 667 */ 668 public Builder setStatus(int status) { 669 mPrototype.mStatus = status; 670 return this; 671 } 672 673 /** 674 * Adds a supported media size. 675 * <p> 676 * <strong>Required:</strong> Yes 677 * </p> 678 * 679 * @param mediaSize A media size. 680 * @param isDefault Whether this is the default. 681 * @return This builder. 682 * @throws IllegalArgumentException If set as default and there 683 * is already a default. 684 * 685 * @see PrintAttributes.MediaSize 686 */ 687 public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) { 688 if (mPrototype.mMediaSizes == null) { 689 mPrototype.mMediaSizes = new ArrayList<MediaSize>(); 690 } 691 final int insertionIndex = mPrototype.mMediaSizes.size(); 692 mPrototype.mMediaSizes.add(mediaSize); 693 if (isDefault) { 694 throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE); 695 mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex; 696 } 697 return this; 698 } 699 700 /** 701 * Adds a supported resolution. 702 * <p> 703 * <strong>Required:</strong> Yes 704 * </p> 705 * 706 * @param resolution A resolution. 707 * @param isDefault Whether this is the default. 708 * @return This builder. 709 * 710 * @throws IllegalArgumentException If set as default and there 711 * is already a default. 712 * 713 * @see PrintAttributes.Resolution 714 */ 715 public Builder addResolution(Resolution resolution, boolean isDefault) { 716 if (mPrototype.mResolutions == null) { 717 mPrototype.mResolutions = new ArrayList<Resolution>(); 718 } 719 final int insertionIndex = mPrototype.mResolutions.size(); 720 mPrototype.mResolutions.add(resolution); 721 if (isDefault) { 722 throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION); 723 mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex; 724 } 725 return this; 726 } 727 728 /** 729 * Sets the minimal margins. 730 * <p> 731 * <strong>Required:</strong> No 732 * </p> 733 * 734 * @param margins The margins. 735 * @param defaultMargins The default margins. 736 * @return This builder. 737 * 738 * @see PrintAttributes.Margins 739 */ 740 public Builder setMinMargins(Margins margins, Margins defaultMargins) { 741 if (margins.getLeftMils() > defaultMargins.getLeftMils() 742 || margins.getTopMils() > defaultMargins.getTopMils() 743 || margins.getRightMils() < defaultMargins.getRightMils() 744 || margins.getBottomMils() < defaultMargins.getBottomMils()) { 745 throw new IllegalArgumentException("Default margins" 746 + " cannot be outside of the min margins."); 747 } 748 mPrototype.mMinMargins = margins; 749 mPrototype.mDefaultMargins = defaultMargins; 750 return this; 751 } 752 753 /** 754 * Adds an input tray. 755 * <p> 756 * <strong>Required:</strong> No 757 * </p> 758 * 759 * @param inputTray A tray. 760 * @param isDefault Whether this is the default. 761 * @return This builder. 762 * 763 * @throws IllegalArgumentException If set as default and there 764 * is already a default. 765 * 766 * @see PrintAttributes.Tray 767 */ 768 public Builder addInputTray(Tray inputTray, boolean isDefault) { 769 if (mPrototype.mInputTrays == null) { 770 mPrototype.mInputTrays = new ArrayList<Tray>(); 771 } 772 final int insertionIndex = mPrototype.mInputTrays.size(); 773 mPrototype.mInputTrays.add(inputTray); 774 if (isDefault) { 775 throwIfDefaultAlreadySpecified(PROPERTY_INPUT_TRAY); 776 mPrototype.mDefaults[PROPERTY_INPUT_TRAY] = insertionIndex; 777 } 778 return this; 779 } 780 781 /** 782 * Adds an output tray. 783 * <p> 784 * <strong>Required:</strong> No 785 * </p> 786 * 787 * @param outputTray A tray. 788 * @param isDefault Whether this is the default. 789 * @return This builder. 790 * 791 * @throws IllegalArgumentException If set as default and there 792 * is already a default. 793 * 794 * @see PrintAttributes.Tray 795 */ 796 public Builder addOutputTray(Tray outputTray, boolean isDefault) { 797 if (mPrototype.mOutputTrays == null) { 798 mPrototype.mOutputTrays = new ArrayList<Tray>(); 799 } 800 final int insertionIndex = mPrototype.mOutputTrays.size(); 801 mPrototype.mOutputTrays.add(outputTray); 802 if (isDefault) { 803 throwIfDefaultAlreadySpecified(PROPERTY_OUTPUT_TRAY); 804 mPrototype.mDefaults[PROPERTY_OUTPUT_TRAY] = insertionIndex; 805 } 806 return this; 807 } 808 809 /** 810 * Sets the color modes. 811 * <p> 812 * <strong>Required:</strong> Yes 813 * </p> 814 * 815 * @param colorModes The color mode bit mask. 816 * @param defaultColorMode The default color mode. 817 * @return This builder. 818 * 819 * @throws IllegalArgumentException If color modes contains an invalid 820 * mode bit or if the default color mode is invalid. 821 * 822 * @see PrintAttributes#COLOR_MODE_COLOR 823 * @see PrintAttributes#COLOR_MODE_MONOCHROME 824 */ 825 public Builder setColorModes(int colorModes, int defaultColorMode) { 826 int currentModes = colorModes; 827 while (currentModes > 0) { 828 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); 829 currentModes &= ~currentMode; 830 PrintAttributes.enforceValidColorMode(currentMode); 831 } 832 if ((colorModes & defaultColorMode) == 0) { 833 throw new IllegalArgumentException("Default color mode not in color modes."); 834 } 835 PrintAttributes.enforceValidColorMode(colorModes); 836 mPrototype.mColorModes = colorModes; 837 mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode; 838 return this; 839 } 840 841 /** 842 * Set the duplex modes. 843 * <p> 844 * <strong>Required:</strong> No 845 * </p> 846 * 847 * @param duplexModes The duplex mode bit mask. 848 * @param defaultDuplexMode The default duplex mode. 849 * @return This builder. 850 * 851 * @throws IllegalArgumentException If duplex modes contains an invalid 852 * mode bit or if the default duplex mode is invalid. 853 * 854 * @see PrintAttributes#DUPLEX_MODE_NONE 855 * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE 856 * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE 857 */ 858 public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) { 859 int currentModes = duplexModes; 860 while (currentModes > 0) { 861 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); 862 currentModes &= ~currentMode; 863 PrintAttributes.enforceValidDuplexMode(currentMode); 864 } 865 if ((duplexModes & defaultDuplexMode) == 0) { 866 throw new IllegalArgumentException("Default duplex mode not in duplex modes."); 867 } 868 PrintAttributes.enforceValidDuplexMode(defaultDuplexMode); 869 mPrototype.mDuplexModes = duplexModes; 870 mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode; 871 return this; 872 } 873 874 /** 875 * Sets the fitting modes. 876 * <p> 877 * <strong>Required:</strong> No 878 * </p> 879 * 880 * @param fittingModes The fitting mode bit mask. 881 * @param defaultFittingMode The default fitting mode. 882 * @return This builder. 883 * 884 * @throws IllegalArgumentException If fitting modes contains an invalid 885 * mode bit or if the default fitting mode is invalid. 886 * 887 * @see PrintAttributes#FITTING_MODE_NONE 888 * @see PrintAttributes#FITTING_MODE_FIT_TO_PAGE 889 */ 890 public Builder setFittingModes(int fittingModes, int defaultFittingMode) { 891 int currentModes = fittingModes; 892 while (currentModes > 0) { 893 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); 894 currentModes &= ~currentMode; 895 PrintAttributes.enfoceValidFittingMode(currentMode); 896 } 897 if ((fittingModes & defaultFittingMode) == 0) { 898 throw new IllegalArgumentException("Default fitting mode not in fiting modes."); 899 } 900 PrintAttributes.enfoceValidFittingMode(defaultFittingMode); 901 mPrototype.mFittingModes = fittingModes; 902 mPrototype.mDefaults[PROPERTY_FITTING_MODE] = defaultFittingMode; 903 return this; 904 } 905 906 /** 907 * Sets the orientations. 908 * <p> 909 * <strong>Required:</strong> Yes 910 * </p> 911 * 912 * @param orientations The orientation bit mask. 913 * @param defaultOrientation The default orientation. 914 * @return This builder. 915 * 916 * @throws IllegalArgumentException If orientations contains an invalid 917 * mode bit or if the default orientation is invalid. 918 * 919 * @see PrintAttributes#ORIENTATION_PORTRAIT 920 * @see PrintAttributes#ORIENTATION_LANDSCAPE 921 */ 922 public Builder setOrientations(int orientations, int defaultOrientation) { 923 int currentOrientaions = orientations; 924 while (currentOrientaions > 0) { 925 final int currentOrnt = (1 << Integer.numberOfTrailingZeros(currentOrientaions)); 926 currentOrientaions &= ~currentOrnt; 927 PrintAttributes.enforceValidOrientation(currentOrnt); 928 } 929 if ((orientations & defaultOrientation) == 0) { 930 throw new IllegalArgumentException("Default orientation not in orientations."); 931 } 932 PrintAttributes.enforceValidOrientation(defaultOrientation); 933 mPrototype.mOrientations = orientations; 934 mPrototype.mDefaults[PROPERTY_ORIENTATION] = defaultOrientation; 935 return this; 936 } 937 938 /** 939 * Crates a new {@link PrinterInfo}. 940 * 941 * @return A new {@link PrinterInfo}. 942 */ 943 public PrinterInfo create() { 944 return new PrinterInfo(mPrototype); 945 } 946 947 private void throwIfDefaultAlreadySpecified(int propertyIndex) { 948 if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) { 949 throw new IllegalArgumentException("Default already specified."); 950 } 951 } 952 } 953 954 public static final Parcelable.Creator<PrinterInfo> CREATOR = 955 new Parcelable.Creator<PrinterInfo>() { 956 @Override 957 public PrinterInfo createFromParcel(Parcel parcel) { 958 return new PrinterInfo(parcel); 959 } 960 961 @Override 962 public PrinterInfo[] newArray(int size) { 963 return new PrinterInfo[size]; 964 } 965 }; 966} 967