PrinterInfo.java revision 85b1f883056a1d74473fd9ce774948878f389ab6
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; 26import android.util.SparseIntArray; 27 28import java.util.ArrayList; 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 53 /** Printer status: the printer is ready to print. */ 54 public static final int STATUS_READY = 1; 55 56 // TODO: Add printer status constants. 57 58 private PrinterId mId; 59 private CharSequence mLabel; 60 private int mStatus; 61 62 private Margins mMinMargins; 63 private final List<MediaSize> mMediaSizes = new ArrayList<MediaSize>(); // required 64 private final List<Resolution> mResolutions = new ArrayList<Resolution>(); // required 65 private List<Tray> mInputTrays; 66 private List<Tray> mOutputTrays; 67 68 private int mDuplexModes; 69 private int mColorModes; 70 private int mFittingModes; 71 private int mOrientations; 72 73 private final SparseIntArray mDefaults = new SparseIntArray(); 74 private Margins mDefaultMargins; 75 76 private PrinterInfo() { 77 mDefaults.put(PROPERTY_MEDIA_SIZE, DEFAULT_UNDEFINED); 78 mDefaults.put(PROPERTY_RESOLUTION, DEFAULT_UNDEFINED); 79 mDefaults.put(PROPERTY_INPUT_TRAY, DEFAULT_UNDEFINED); 80 mDefaults.put(PROPERTY_OUTPUT_TRAY, DEFAULT_UNDEFINED); 81 mDefaults.put(PROPERTY_DUPLEX_MODE, DEFAULT_UNDEFINED); 82 mDefaults.put(PROPERTY_COLOR_MODE, DEFAULT_UNDEFINED); 83 mDefaults.put(PROPERTY_FITTING_MODE, DEFAULT_UNDEFINED); 84 mDefaults.put(PROPERTY_ORIENTATION, DEFAULT_UNDEFINED); 85 } 86 87 private PrinterInfo(PrinterInfo prototype) { 88 mId = prototype.mId; 89 mLabel = prototype.mLabel; 90 mStatus = prototype.mStatus; 91 92 mMinMargins = prototype.mMinMargins; 93 mMediaSizes.addAll(prototype.mMediaSizes); 94 mResolutions.addAll(prototype.mResolutions); 95 mInputTrays = (prototype.mInputTrays != null) 96 ? new ArrayList<Tray>(prototype.mInputTrays) : null; 97 mOutputTrays = (prototype.mOutputTrays != null) 98 ? new ArrayList<Tray>(prototype.mOutputTrays) : null; 99 100 mDuplexModes = prototype.mDuplexModes; 101 mColorModes = prototype.mColorModes; 102 mFittingModes = prototype.mFittingModes; 103 mOrientations = prototype.mOrientations; 104 105 final int defaultCount = prototype.mDefaults.size(); 106 for (int i = 0; i < defaultCount; i++) { 107 mDefaults.put(prototype.mDefaults.keyAt(i), prototype.mDefaults.valueAt(i)); 108 } 109 mDefaultMargins = prototype.mDefaultMargins; 110 } 111 112 /** 113 * Get the globally unique printer id. 114 * 115 * @return The printer id. 116 */ 117 public PrinterId getId() { 118 return mId; 119 } 120 121 /** 122 * Gets the human readable printer label. 123 * 124 * @return The human readable label. 125 */ 126 public CharSequence getLabel() { 127 return mLabel; 128 } 129 130 /** 131 * Gets the status of the printer. 132 * 133 * @return The status. 134 */ 135 public int getStatus() { 136 return mStatus; 137 } 138 139 /** 140 * Gets the supported media sizes. 141 * 142 * @return The supported media sizes. 143 */ 144 public List<MediaSize> getMediaSizes() { 145 return mMediaSizes; 146 } 147 148 /** 149 * Gets the supported resolutions. 150 * 151 * @return The supported resolutions. 152 */ 153 public List<Resolution> getResolutions() { 154 return mResolutions; 155 } 156 157 /** 158 * Gets the minimal supported margins. 159 * 160 * @return The minimal margins. 161 */ 162 public Margins getMinMargins() { 163 return mMinMargins; 164 } 165 166 /** 167 * Gets the available input trays. 168 * 169 * @return The input trays. 170 */ 171 public List<Tray> getInputTrays() { 172 return mInputTrays; 173 } 174 175 /** 176 * Gets the available output trays. 177 * 178 * @return The output trays. 179 */ 180 public List<Tray> getOutputTrays() { 181 return mOutputTrays; 182 } 183 184 /** 185 * Gets the supported duplex modes. 186 * 187 * @return The duplex modes. 188 * 189 * @see PrintAttributes#DUPLEX_MODE_NONE 190 * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE 191 * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE 192 */ 193 public int getDuplexModes() { 194 return mDuplexModes; 195 } 196 197 /** 198 * Gets the supported color modes. 199 * 200 * @return The color modes. 201 * 202 * @see PrintAttributes#COLOR_MODE_COLOR 203 * @see PrintAttributes#COLOR_MODE_MONOCHROME 204 */ 205 public int getColorModes() { 206 return mColorModes; 207 } 208 209 /** 210 * Gets the supported fitting modes. 211 * 212 * @return The fitting modes. 213 * 214 * @see PrintAttributes#FITTING_MODE_NONE 215 * @see PrintAttributes#FITTING_MODE_FIT_TO_PAGE 216 */ 217 public int getFittingModes() { 218 return mFittingModes; 219 } 220 221 /** 222 * Gets the supported orientations. 223 * 224 * @return The orientations. 225 * 226 * @see PrintAttributes#ORIENTATION_PORTRAIT 227 * @see PrintAttributes#ORIENTATION_LANDSCAPE 228 */ 229 public int getOrientations() { 230 return mOrientations; 231 } 232 233 /** 234 * Gets the default print attributes. 235 * 236 * @param outAttributes The attributes to populated. 237 */ 238 public void getDefaults(PrintAttributes outAttributes) { 239 outAttributes.clear(); 240 241 outAttributes.setMargins(mDefaultMargins); 242 243 final int mediaSizeIndex = mDefaults.get(PROPERTY_MEDIA_SIZE); 244 if (mediaSizeIndex >= 0) { 245 outAttributes.setMediaSize(mMediaSizes.get(mediaSizeIndex)); 246 } 247 248 final int resolutionIndex = mDefaults.get(PROPERTY_RESOLUTION); 249 if (resolutionIndex >= 0) { 250 outAttributes.setResolution(mResolutions.get(resolutionIndex)); 251 } 252 253 final int inputTrayIndex = mDefaults.get(PROPERTY_INPUT_TRAY); 254 if (inputTrayIndex >= 0) { 255 outAttributes.setInputTray(mInputTrays.get(inputTrayIndex)); 256 } 257 258 final int outputTrayIndex = mDefaults.get(PROPERTY_OUTPUT_TRAY); 259 if (outputTrayIndex >= 0) { 260 outAttributes.setOutputTray(mOutputTrays.get(outputTrayIndex)); 261 } 262 263 final int duplexMode = mDefaults.get(PROPERTY_DUPLEX_MODE); 264 if (duplexMode > 0) { 265 outAttributes.setDuplexMode(duplexMode); 266 } 267 268 final int colorMode = mDefaults.get(PROPERTY_COLOR_MODE); 269 if (colorMode > 0) { 270 outAttributes.setColorMode(mColorModes & colorMode); 271 } 272 273 final int fittingMode = mDefaults.get(PROPERTY_FITTING_MODE); 274 if (fittingMode > 0) { 275 outAttributes.setFittingMode(fittingMode); 276 } 277 278 final int orientation = mDefaults.get(PROPERTY_ORIENTATION); 279 if (orientation > 0) { 280 outAttributes.setOrientation(orientation); 281 } 282 } 283 284 private PrinterInfo(Parcel parcel) { 285 mId = parcel.readParcelable(null); 286 mLabel = parcel.readCharSequence(); 287 mStatus = parcel.readInt(); 288 289 mMinMargins = readMargins(parcel); 290 readMediaSizes(parcel); 291 readResolutions(parcel); 292 mInputTrays = readInputTrays(parcel); 293 mOutputTrays = readOutputTrays(parcel); 294 295 mColorModes = parcel.readInt(); 296 mDuplexModes = parcel.readInt(); 297 mFittingModes = parcel.readInt(); 298 mOrientations = parcel.readInt(); 299 300 readDefaults(parcel); 301 mDefaultMargins = readMargins(parcel); 302 } 303 304 @Override 305 public int describeContents() { 306 return 0; 307 } 308 309 @Override 310 public void writeToParcel(Parcel parcel, int flags) { 311 parcel.writeParcelable(mId, flags); 312 parcel.writeCharSequence(mLabel); 313 parcel.writeInt(mStatus); 314 315 writeMargins(mMinMargins, parcel); 316 writeMediaSizes(parcel); 317 writeResolutions(parcel); 318 writeInputTrays(parcel); 319 writeOutputTrays(parcel); 320 321 parcel.writeInt(mColorModes); 322 parcel.writeInt(mDuplexModes); 323 parcel.writeInt(mFittingModes); 324 parcel.writeInt(mOrientations); 325 326 writeDefaults(parcel); 327 writeMargins(mDefaultMargins, parcel); 328 } 329 330 @Override 331 public String toString() { 332 StringBuilder builder = new StringBuilder(); 333 builder.append("PrinterInfo{"); 334 builder.append(mId).append(", \""); 335 builder.append(mLabel); 336 builder.append("\"}"); 337 return builder.toString(); 338 } 339 340 private void writeMediaSizes(Parcel parcel) { 341 if (mMediaSizes == null) { 342 parcel.writeInt(0); 343 return; 344 } 345 final int mediaSizeCount = mMediaSizes.size(); 346 parcel.writeInt(mediaSizeCount); 347 for (int i = 0; i < mediaSizeCount; i++) { 348 mMediaSizes.get(i).writeToParcel(parcel); 349 } 350 } 351 352 private void readMediaSizes(Parcel parcel) { 353 final int mediaSizeCount = parcel.readInt(); 354 for (int i = 0; i < mediaSizeCount; i++) { 355 mMediaSizes.add(MediaSize.createFromParcel(parcel)); 356 } 357 } 358 359 private void writeResolutions(Parcel parcel) { 360 final int resolutionCount = mResolutions.size(); 361 parcel.writeInt(resolutionCount); 362 for (int i = 0; i < resolutionCount; i++) { 363 mResolutions.get(i).writeToParcel(parcel); 364 } 365 } 366 367 private void readResolutions(Parcel parcel) { 368 final int resolutionCount = parcel.readInt(); 369 for (int i = 0; i < resolutionCount; i++) { 370 mResolutions.add(Resolution.createFromParcel(parcel)); 371 } 372 } 373 374 private void writeMargins(Margins margins, Parcel parcel) { 375 if (margins == null) { 376 parcel.writeInt(0); 377 } else { 378 parcel.writeInt(1); 379 margins.writeToParcel(parcel); 380 } 381 } 382 383 private Margins readMargins(Parcel parcel) { 384 return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null; 385 } 386 387 private void writeInputTrays(Parcel parcel) { 388 if (mInputTrays == null) { 389 parcel.writeInt(0); 390 return; 391 } 392 final int inputTrayCount = mInputTrays.size(); 393 parcel.writeInt(inputTrayCount); 394 for (int i = 0; i < inputTrayCount; i++) { 395 mInputTrays.get(i).writeToParcel(parcel); 396 } 397 } 398 399 private List<Tray> readInputTrays(Parcel parcel) { 400 final int inputTrayCount = parcel.readInt(); 401 if (inputTrayCount <= 0) { 402 return null; 403 } 404 List<Tray> inputTrays = new ArrayList<Tray>(inputTrayCount); 405 for (int i = 0; i < inputTrayCount; i++) { 406 inputTrays.add(Tray.createFromParcel(parcel)); 407 } 408 return inputTrays; 409 } 410 411 private void writeOutputTrays(Parcel parcel) { 412 if (mOutputTrays == null) { 413 parcel.writeInt(0); 414 return; 415 } 416 final int outputTrayCount = mOutputTrays.size(); 417 parcel.writeInt(outputTrayCount); 418 for (int i = 0; i < outputTrayCount; i++) { 419 mOutputTrays.get(i).writeToParcel(parcel); 420 } 421 } 422 423 private List<Tray> readOutputTrays(Parcel parcel) { 424 final int outputTrayCount = parcel.readInt(); 425 if (outputTrayCount <= 0) { 426 return null; 427 } 428 List<Tray> outputTrays = new ArrayList<Tray>(outputTrayCount); 429 for (int i = 0; i < outputTrayCount; i++) { 430 outputTrays.add(Tray.createFromParcel(parcel)); 431 } 432 return outputTrays; 433 } 434 435 private void readDefaults(Parcel parcel) { 436 final int defaultCount = parcel.readInt(); 437 for (int i = 0; i < defaultCount; i++) { 438 mDefaults.append(mDefaults.size(), parcel.readInt()); 439 } 440 } 441 442 private void writeDefaults(Parcel parcel) { 443 final int defaultCount = mDefaults.size(); 444 parcel.writeInt(defaultCount); 445 for (int i = 0; i < defaultCount; i++) { 446 parcel.writeInt(mDefaults.valueAt(i)); 447 } 448 } 449 450 /** 451 * Builder for creating of a {@link PrinterInfo}. This class is responsible 452 * to enforce that all required attributes have at least one default value. 453 * In other words, this class creates only well-formed {@link PrinterInfo}s. 454 * <p> 455 * Look at the individual methods for a reference whether a property is 456 * required or if it is optional. 457 * </p> 458 */ 459 public static final class Builder { 460 private final PrinterInfo mPrototype; 461 462 /** 463 * Creates a new instance. 464 * 465 * @param printerId The printer id. 466 * @param label The human readable printer label. 467 * 468 * @throws IllegalArgumentException IF the printer id is null. 469 * @throws IllegalArgumentException IF the label is empty. 470 */ 471 public Builder(PrinterId printerId, CharSequence label) { 472 if (printerId == null) { 473 throw new IllegalArgumentException("printerId cannot be null."); 474 } 475 if (TextUtils.isEmpty(label)) { 476 throw new IllegalArgumentException("label cannot be empty."); 477 } 478 mPrototype = new PrinterInfo(); 479 mPrototype.mLabel = label; 480 mPrototype.mId = printerId; 481 } 482 483 /** 484 * Sets the printer status. 485 * <p> 486 * <strong>Required:</strong> Yes 487 * </p> 488 * 489 * @param status The status. 490 * @return This builder. 491 */ 492 public Builder setStatus(int status) { 493 mPrototype.mStatus = status; 494 return this; 495 } 496 497 /** 498 * Adds a supported media size. 499 * <p> 500 * <strong>Required:</strong> Yes 501 * </p> 502 * 503 * @param mediaSize A media size. 504 * @param isDefault Whether this is the default. 505 * @return This builder. 506 * @throws IllegalArgumentException If set as default and there 507 * is already a default. 508 * 509 * @see PrintAttributes.MediaSize 510 */ 511 public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) { 512 final int insertionIndex = mPrototype.mMediaSizes.size(); 513 mPrototype.mMediaSizes.add(mediaSize); 514 if (isDefault) { 515 throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE); 516 mPrototype.mDefaults.put(PROPERTY_MEDIA_SIZE, insertionIndex); 517 } 518 return this; 519 } 520 521 /** 522 * Adds a supported resolution. 523 * <p> 524 * <strong>Required:</strong> Yes 525 * </p> 526 * 527 * @param resolution A resolution. 528 * @param isDefault Whether this is the default. 529 * @return This builder. 530 * 531 * @throws IllegalArgumentException If set as default and there 532 * is already a default. 533 * 534 * @see PrintAttributes.Resolution 535 */ 536 public Builder addResolution(Resolution resolution, boolean isDefault) { 537 final int insertionIndex = mPrototype.mResolutions.size(); 538 mPrototype.mResolutions.add(resolution); 539 if (isDefault) { 540 throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION); 541 mPrototype.mDefaults.put(PROPERTY_RESOLUTION, insertionIndex); 542 } 543 return this; 544 } 545 546 /** 547 * Sets the minimal margins. 548 * <p> 549 * <strong>Required:</strong> No 550 * </p> 551 * 552 * @param margins The margins. 553 * @param defaultMargins The default margins. 554 * @return This builder. 555 * 556 * @see PrintAttributes.Margins 557 */ 558 public Builder setMinMargins(Margins margins, Margins defaultMargins) { 559 if (margins.getLeftMils() > defaultMargins.getLeftMils() 560 || margins.getTopMils() > defaultMargins.getTopMils() 561 || margins.getRightMils() < defaultMargins.getRightMils() 562 || margins.getBottomMils() < defaultMargins.getBottomMils()) { 563 throw new IllegalArgumentException("Default margins" 564 + " cannot be outside of the min margins."); 565 } 566 mPrototype.mMinMargins = margins; 567 mPrototype.mDefaultMargins = defaultMargins; 568 return this; 569 } 570 571 /** 572 * Adds an input tray. 573 * <p> 574 * <strong>Required:</strong> No 575 * </p> 576 * 577 * @param inputTray A tray. 578 * @param isDefault Whether this is the default. 579 * @return This builder. 580 * 581 * @throws IllegalArgumentException If set as default and there 582 * is already a default. 583 * 584 * @see PrintAttributes.Tray 585 */ 586 public Builder addInputTray(Tray inputTray, boolean isDefault) { 587 if (mPrototype.mInputTrays == null) { 588 mPrototype.mInputTrays = new ArrayList<Tray>(); 589 } 590 final int insertionIndex = mPrototype.mInputTrays.size(); 591 mPrototype.mInputTrays.add(inputTray); 592 if (isDefault) { 593 throwIfDefaultAlreadySpecified(PROPERTY_INPUT_TRAY); 594 mPrototype.mDefaults.put(PROPERTY_INPUT_TRAY, insertionIndex); 595 } 596 return this; 597 } 598 599 /** 600 * Adds an output tray. 601 * <p> 602 * <strong>Required:</strong> No 603 * </p> 604 * 605 * @param outputTray A tray. 606 * @param isDefault Whether this is the default. 607 * @return This builder. 608 * 609 * @throws IllegalArgumentException If set as default and there 610 * is already a default. 611 * 612 * @see PrintAttributes.Tray 613 */ 614 public Builder addOutputTray(Tray outputTray, boolean isDefault) { 615 if (mPrototype.mOutputTrays == null) { 616 mPrototype.mOutputTrays = new ArrayList<Tray>(); 617 } 618 final int insertionIndex = mPrototype.mOutputTrays.size(); 619 mPrototype.mOutputTrays.add(outputTray); 620 if (isDefault) { 621 throwIfDefaultAlreadySpecified(PROPERTY_OUTPUT_TRAY); 622 mPrototype.mDefaults.put(PROPERTY_OUTPUT_TRAY, insertionIndex); 623 } 624 return this; 625 } 626 627 /** 628 * Sets the color modes. 629 * <p> 630 * <strong>Required:</strong> Yes 631 * </p> 632 * 633 * @param colorModes The color mode bit mask. 634 * @param defaultColorMode The default color mode. 635 * @return This builder. 636 * 637 * @throws IllegalArgumentException If color modes contains an invalid 638 * mode bit or if the default color mode is invalid. 639 * 640 * @see PrintAttributes#COLOR_MODE_COLOR 641 * @see PrintAttributes#COLOR_MODE_MONOCHROME 642 */ 643 public Builder setColorModes(int colorModes, int defaultColorMode) { 644 int currentModes = colorModes; 645 while (currentModes > 0) { 646 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); 647 currentModes &= ~currentMode; 648 PrintAttributes.enforceValidColorMode(currentMode); 649 } 650 if ((colorModes & defaultColorMode) == 0) { 651 throw new IllegalArgumentException("Default color mode not in color modes."); 652 } 653 PrintAttributes.enforceValidColorMode(colorModes); 654 mPrototype.mColorModes = colorModes; 655 mPrototype.mDefaults.put(PROPERTY_COLOR_MODE, defaultColorMode); 656 return this; 657 } 658 659 /** 660 * Set the duplex modes. 661 * <p> 662 * <strong>Required:</strong> No 663 * </p> 664 * 665 * @param duplexModes The duplex mode bit mask. 666 * @param defaultDuplexMode The default duplex mode. 667 * @return This builder. 668 * 669 * @throws IllegalArgumentException If duplex modes contains an invalid 670 * mode bit or if the default duplex mode is invalid. 671 * 672 * @see PrintAttributes#DUPLEX_MODE_NONE 673 * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE 674 * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE 675 */ 676 public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) { 677 int currentModes = duplexModes; 678 while (currentModes > 0) { 679 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); 680 currentModes &= ~currentMode; 681 PrintAttributes.enforceValidDuplexMode(currentMode); 682 } 683 if ((duplexModes & defaultDuplexMode) == 0) { 684 throw new IllegalArgumentException("Default duplex mode not in duplex modes."); 685 } 686 PrintAttributes.enforceValidDuplexMode(defaultDuplexMode); 687 mPrototype.mDuplexModes = duplexModes; 688 mPrototype.mDefaults.put(PROPERTY_DUPLEX_MODE, defaultDuplexMode); 689 return this; 690 } 691 692 /** 693 * Sets the fitting modes. 694 * <p> 695 * <strong>Required:</strong> No 696 * </p> 697 * 698 * @param fittingModes The fitting mode bit mask. 699 * @param defaultFittingMode The default fitting mode. 700 * @return This builder. 701 * 702 * @throws IllegalArgumentException If fitting modes contains an invalid 703 * mode bit or if the default fitting mode is invalid. 704 * 705 * @see PrintAttributes#FITTING_MODE_NONE 706 * @see PrintAttributes#FITTING_MODE_FIT_TO_PAGE 707 */ 708 public Builder setFittingModes(int fittingModes, int defaultFittingMode) { 709 int currentModes = fittingModes; 710 while (currentModes > 0) { 711 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); 712 currentModes &= ~currentMode; 713 PrintAttributes.enfoceValidFittingMode(currentMode); 714 } 715 if ((fittingModes & defaultFittingMode) == 0) { 716 throw new IllegalArgumentException("Default fitting mode not in fiting modes."); 717 } 718 PrintAttributes.enfoceValidFittingMode(defaultFittingMode); 719 mPrototype.mFittingModes = fittingModes; 720 mPrototype.mDefaults.put(PROPERTY_FITTING_MODE, defaultFittingMode); 721 return this; 722 } 723 724 /** 725 * Sets the orientations. 726 * <p> 727 * <strong>Required:</strong> Yes 728 * </p> 729 * 730 * @param orientations The orientation bit mask. 731 * @param defaultOrientation The default orientation. 732 * @return This builder. 733 * 734 * @throws IllegalArgumentException If orientations contains an invalid 735 * mode bit or if the default orientation is invalid. 736 * 737 * @see PrintAttributes#ORIENTATION_PORTRAIT 738 * @see PrintAttributes#ORIENTATION_LANDSCAPE 739 */ 740 public Builder setOrientations(int orientations, int defaultOrientation) { 741 int currentOrientaions = orientations; 742 while (currentOrientaions > 0) { 743 final int currentOrnt = (1 << Integer.numberOfTrailingZeros(currentOrientaions)); 744 currentOrientaions &= ~currentOrnt; 745 PrintAttributes.enforceValidOrientation(currentOrnt); 746 } 747 if ((orientations & defaultOrientation) == 0) { 748 throw new IllegalArgumentException("Default orientation not in orientations."); 749 } 750 PrintAttributes.enforceValidOrientation(defaultOrientation); 751 mPrototype.mOrientations = orientations; 752 mPrototype.mDefaults.put(PROPERTY_ORIENTATION, defaultOrientation); 753 return this; 754 } 755 756 /** 757 * Crates a new {@link PrinterInfo} enforcing that all required properties 758 * have need specified. See individual methods in this class for reference 759 * about required attributes. 760 * 761 * @return A new {@link PrinterInfo}. 762 * 763 * @throws IllegalStateException If a required attribute was not specified. 764 */ 765 public PrinterInfo create() { 766 if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) { 767 throw new IllegalStateException("No media size specified."); 768 } 769 if (mPrototype.mDefaults.valueAt(PROPERTY_MEDIA_SIZE) == DEFAULT_UNDEFINED) { 770 throw new IllegalStateException("No default media size specified."); 771 } 772 if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) { 773 throw new IllegalStateException("No resolution specified."); 774 } 775 if (mPrototype.mDefaults.valueAt(PROPERTY_RESOLUTION) == DEFAULT_UNDEFINED) { 776 throw new IllegalStateException("No default resolution specified."); 777 } 778 if (mPrototype.mColorModes == 0) { 779 throw new IllegalStateException("No color mode specified."); 780 } 781 if (mPrototype.mDefaults.valueAt(PROPERTY_COLOR_MODE) == DEFAULT_UNDEFINED) { 782 throw new IllegalStateException("No default color mode specified."); 783 } 784 if (mPrototype.mOrientations == 0) { 785 throw new IllegalStateException("No oprientation specified."); 786 } 787 if (mPrototype.mDefaults.valueAt(PROPERTY_ORIENTATION) == DEFAULT_UNDEFINED) { 788 throw new IllegalStateException("No default orientation specified."); 789 } 790 if (mPrototype.mMinMargins == null) { 791 mPrototype.mMinMargins = new Margins(0, 0, 0, 0); 792 } 793 if (mPrototype.mDefaultMargins == null) { 794 mPrototype.mDefaultMargins = mPrototype.mMinMargins; 795 } 796 return new PrinterInfo(mPrototype); 797 } 798 799 private void throwIfDefaultAlreadySpecified(int propertyIndex) { 800 if (mPrototype.mDefaults.get(propertyIndex) != DEFAULT_UNDEFINED) { 801 throw new IllegalArgumentException("Default already specified."); 802 } 803 } 804 } 805 806 public static final Parcelable.Creator<PrinterInfo> CREATOR = 807 new Parcelable.Creator<PrinterInfo>() { 808 @Override 809 public PrinterInfo createFromParcel(Parcel parcel) { 810 return new PrinterInfo(parcel); 811 } 812 813 @Override 814 public PrinterInfo[] newArray(int size) { 815 return new PrinterInfo[size]; 816 } 817 }; 818} 819