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