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