blob: 01c23f6734b05cd8d2f8f3cbff0483ea6b6d4521 [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
Philip P. Moltmannc43639c2015-12-18 13:58:40 -080019import android.annotation.NonNull;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070020import android.os.Parcel;
21import android.os.Parcelable;
Philip P. Moltmannc43639c2015-12-18 13:58:40 -080022import android.print.PrintAttributes.ColorMode;
23import android.print.PrintAttributes.DuplexMode;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070024import android.print.PrintAttributes.Margins;
25import android.print.PrintAttributes.MediaSize;
26import android.print.PrintAttributes.Resolution;
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -070027import com.android.internal.util.Preconditions;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070028
29import java.util.ArrayList;
30import java.util.Arrays;
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -070031import java.util.Collections;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070032import java.util.List;
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -070033import java.util.function.IntConsumer;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070034
35/**
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -070036 * This class represents the capabilities of a printer. Instances
37 * of this class are created by a print service to report the
38 * capabilities of a printer it manages. The capabilities of a
39 * printer specify how it can print content. For example, what
40 * are the media sizes supported by the printer, what are the
41 * minimal margins of the printer based on its technical design,
42 * etc.
Svetoslav Ganov798bed62013-08-11 12:29:39 -070043 */
44public final class PrinterCapabilitiesInfo implements Parcelable {
45 /**
46 * Undefined default value.
47 *
48 * @hide
49 */
50 public static final int DEFAULT_UNDEFINED = -1;
51
52 private static final int PROPERTY_MEDIA_SIZE = 0;
53 private static final int PROPERTY_RESOLUTION = 1;
Svetoslav773f54d2013-09-03 14:01:43 -070054 private static final int PROPERTY_COLOR_MODE = 2;
Svetoslav948c9a62015-02-02 19:47:04 -080055 private static final int PROPERTY_DUPLEX_MODE = 3;
56 private static final int PROPERTY_COUNT = 4;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070057
58 private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
59
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -070060 private @NonNull Margins mMinMargins = DEFAULT_MARGINS;
61 private @NonNull List<MediaSize> mMediaSizes;
62 private @NonNull List<Resolution> mResolutions;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070063
Svetoslav Ganov798bed62013-08-11 12:29:39 -070064 private int mColorModes;
Svetoslav948c9a62015-02-02 19:47:04 -080065 private int mDuplexModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070066
67 private final int[] mDefaults = new int[PROPERTY_COUNT];
Svetoslav Ganov798bed62013-08-11 12:29:39 -070068
69 /**
70 * @hide
71 */
72 public PrinterCapabilitiesInfo() {
73 Arrays.fill(mDefaults, DEFAULT_UNDEFINED);
74 }
75
76 /**
77 * @hide
78 */
79 public PrinterCapabilitiesInfo(PrinterCapabilitiesInfo prototype) {
80 copyFrom(prototype);
81 }
82
83 /**
84 * @hide
85 */
86 public void copyFrom(PrinterCapabilitiesInfo other) {
Svetoslav651dd4e2013-09-12 14:37:47 -070087 if (this == other) {
88 return;
89 }
90
Svetoslav Ganov798bed62013-08-11 12:29:39 -070091 mMinMargins = other.mMinMargins;
92
93 if (other.mMediaSizes != null) {
94 if (mMediaSizes != null) {
95 mMediaSizes.clear();
96 mMediaSizes.addAll(other.mMediaSizes);
97 } else {
98 mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes);
99 }
100 } else {
101 mMediaSizes = null;
102 }
103
104 if (other.mResolutions != null) {
105 if (mResolutions != null) {
106 mResolutions.clear();
107 mResolutions.addAll(other.mResolutions);
108 } else {
109 mResolutions = new ArrayList<Resolution>(other.mResolutions);
110 }
111 } else {
112 mResolutions = null;
113 }
114
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700115 mColorModes = other.mColorModes;
Svetoslav948c9a62015-02-02 19:47:04 -0800116 mDuplexModes = other.mDuplexModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700117
118 final int defaultCount = other.mDefaults.length;
119 for (int i = 0; i < defaultCount; i++) {
120 mDefaults[i] = other.mDefaults[i];
121 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700122 }
123
124 /**
125 * Gets the supported media sizes.
126 *
127 * @return The media sizes.
128 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800129 public @NonNull List<MediaSize> getMediaSizes() {
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700130 return Collections.unmodifiableList(mMediaSizes);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700131 }
132
133 /**
134 * Gets the supported resolutions.
135 *
136 * @return The resolutions.
137 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800138 public @NonNull List<Resolution> getResolutions() {
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700139 return Collections.unmodifiableList(mResolutions);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700140 }
141
142 /**
Svetoslav651dd4e2013-09-12 14:37:47 -0700143 * Gets the minimal margins. These are the minimal margins
144 * the printer physically supports.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700145 *
146 * @return The minimal margins.
147 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800148 public @NonNull Margins getMinMargins() {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700149 return mMinMargins;
150 }
151
152 /**
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700153 * Gets the bit mask of supported color modes.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700154 *
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700155 * @return The bit mask of supported color modes.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700156 *
157 * @see PrintAttributes#COLOR_MODE_COLOR
158 * @see PrintAttributes#COLOR_MODE_MONOCHROME
159 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800160 public @ColorMode int getColorModes() {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700161 return mColorModes;
162 }
163
164 /**
Svetoslav948c9a62015-02-02 19:47:04 -0800165 * Gets the bit mask of supported duplex modes.
166 *
167 * @return The bit mask of supported duplex modes.
168 *
169 * @see PrintAttributes#DUPLEX_MODE_NONE
170 * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
171 * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
172 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800173 public @DuplexMode int getDuplexModes() {
Svetoslav948c9a62015-02-02 19:47:04 -0800174 return mDuplexModes;
175 }
176
177 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700178 * Gets the default print attributes.
179 *
Svetoslav651dd4e2013-09-12 14:37:47 -0700180 * @return The default attributes.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700181 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800182 public @NonNull PrintAttributes getDefaults() {
Svetoslav651dd4e2013-09-12 14:37:47 -0700183 PrintAttributes.Builder builder = new PrintAttributes.Builder();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700184
Svetoslav651dd4e2013-09-12 14:37:47 -0700185 builder.setMinMargins(mMinMargins);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700186
187 final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
188 if (mediaSizeIndex >= 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700189 builder.setMediaSize(mMediaSizes.get(mediaSizeIndex));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700190 }
191
192 final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
193 if (resolutionIndex >= 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700194 builder.setResolution(mResolutions.get(resolutionIndex));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700195 }
196
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700197 final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
198 if (colorMode > 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700199 builder.setColorMode(colorMode);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700200 }
Svetoslav651dd4e2013-09-12 14:37:47 -0700201
Svetoslav948c9a62015-02-02 19:47:04 -0800202 final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE];
203 if (duplexMode > 0) {
204 builder.setDuplexMode(duplexMode);
205 }
206
Svetoslav651dd4e2013-09-12 14:37:47 -0700207 return builder.build();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700208 }
209
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -0700210 /**
211 * Call enforceSingle for each bit in the mask.
212 *
213 * @param mask The mask
214 * @param enforceSingle The function to call
215 */
216 private static void enforceValidMask(int mask, IntConsumer enforceSingle) {
217 int current = mask;
218 while (current > 0) {
219 final int currentMode = (1 << Integer.numberOfTrailingZeros(current));
220 current &= ~currentMode;
221 enforceSingle.accept(currentMode);
222 }
223 }
224
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700225 private PrinterCapabilitiesInfo(Parcel parcel) {
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -0700226 mMinMargins = Preconditions.checkNotNull(readMargins(parcel));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700227 readMediaSizes(parcel);
228 readResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700229
230 mColorModes = parcel.readInt();
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -0700231 enforceValidMask(mColorModes,
232 (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
233
Svetoslav948c9a62015-02-02 19:47:04 -0800234 mDuplexModes = parcel.readInt();
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -0700235 enforceValidMask(mDuplexModes,
Philip P. Moltmann0d1407e2016-04-01 12:17:10 -0700236 (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700237
238 readDefaults(parcel);
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -0700239 Preconditions.checkArgument(mMediaSizes.size() > mDefaults[PROPERTY_MEDIA_SIZE]);
240 Preconditions.checkArgument(mResolutions.size() > mDefaults[PROPERTY_RESOLUTION]);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700241 }
242
243 @Override
244 public int describeContents() {
245 return 0;
246 }
247
248 @Override
249 public void writeToParcel(Parcel parcel, int flags) {
250 writeMargins(mMinMargins, parcel);
251 writeMediaSizes(parcel);
252 writeResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700253
254 parcel.writeInt(mColorModes);
Svetoslav948c9a62015-02-02 19:47:04 -0800255 parcel.writeInt(mDuplexModes);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700256
257 writeDefaults(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700258 }
259
260 @Override
261 public int hashCode() {
262 final int prime = 31;
263 int result = 1;
264 result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
265 result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
266 result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700267 result = prime * result + mColorModes;
Svetoslav948c9a62015-02-02 19:47:04 -0800268 result = prime * result + mDuplexModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700269 result = prime * result + Arrays.hashCode(mDefaults);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700270 return result;
271 }
272
273 @Override
274 public boolean equals(Object obj) {
275 if (this == obj) {
276 return true;
277 }
278 if (obj == null) {
279 return false;
280 }
281 if (getClass() != obj.getClass()) {
282 return false;
283 }
284 PrinterCapabilitiesInfo other = (PrinterCapabilitiesInfo) obj;
285 if (mMinMargins == null) {
286 if (other.mMinMargins != null) {
287 return false;
288 }
289 } else if (!mMinMargins.equals(other.mMinMargins)) {
290 return false;
291 }
292 if (mMediaSizes == null) {
293 if (other.mMediaSizes != null) {
294 return false;
295 }
296 } else if (!mMediaSizes.equals(other.mMediaSizes)) {
297 return false;
298 }
299 if (mResolutions == null) {
300 if (other.mResolutions != null) {
301 return false;
302 }
303 } else if (!mResolutions.equals(other.mResolutions)) {
304 return false;
305 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700306 if (mColorModes != other.mColorModes) {
307 return false;
308 }
Svetoslav948c9a62015-02-02 19:47:04 -0800309 if (mDuplexModes != other.mDuplexModes) {
310 return false;
311 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700312 if (!Arrays.equals(mDefaults, other.mDefaults)) {
313 return false;
314 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700315 return true;
316 }
317
318 @Override
319 public String toString() {
320 StringBuilder builder = new StringBuilder();
321 builder.append("PrinterInfo{");
322 builder.append("minMargins=").append(mMinMargins);
323 builder.append(", mediaSizes=").append(mMediaSizes);
324 builder.append(", resolutions=").append(mResolutions);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700325 builder.append(", colorModes=").append(colorModesToString());
Svetoslav948c9a62015-02-02 19:47:04 -0800326 builder.append(", duplexModes=").append(duplexModesToString());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700327 builder.append("\"}");
328 return builder.toString();
329 }
330
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700331 private String colorModesToString() {
332 StringBuilder builder = new StringBuilder();
333 builder.append('[');
334 int colorModes = mColorModes;
335 while (colorModes != 0) {
336 final int colorMode = 1 << Integer.numberOfTrailingZeros(colorModes);
337 colorModes &= ~colorMode;
Svetoslav651dd4e2013-09-12 14:37:47 -0700338 if (builder.length() > 1) {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700339 builder.append(", ");
340 }
341 builder.append(PrintAttributes.colorModeToString(colorMode));
342 }
343 builder.append(']');
344 return builder.toString();
345 }
346
Svetoslav948c9a62015-02-02 19:47:04 -0800347 private String duplexModesToString() {
348 StringBuilder builder = new StringBuilder();
349 builder.append('[');
350 int duplexModes = mDuplexModes;
351 while (duplexModes != 0) {
352 final int duplexMode = 1 << Integer.numberOfTrailingZeros(duplexModes);
353 duplexModes &= ~duplexMode;
354 if (builder.length() > 1) {
355 builder.append(", ");
356 }
357 builder.append(PrintAttributes.duplexModeToString(duplexMode));
358 }
359 builder.append(']');
360 return builder.toString();
361 }
362
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700363 private void writeMediaSizes(Parcel parcel) {
364 if (mMediaSizes == null) {
365 parcel.writeInt(0);
366 return;
367 }
368 final int mediaSizeCount = mMediaSizes.size();
369 parcel.writeInt(mediaSizeCount);
370 for (int i = 0; i < mediaSizeCount; i++) {
371 mMediaSizes.get(i).writeToParcel(parcel);
372 }
373 }
374
375 private void readMediaSizes(Parcel parcel) {
376 final int mediaSizeCount = parcel.readInt();
377 if (mediaSizeCount > 0 && mMediaSizes == null) {
378 mMediaSizes = new ArrayList<MediaSize>();
379 }
380 for (int i = 0; i < mediaSizeCount; i++) {
381 mMediaSizes.add(MediaSize.createFromParcel(parcel));
382 }
383 }
384
385 private void writeResolutions(Parcel parcel) {
386 if (mResolutions == null) {
387 parcel.writeInt(0);
388 return;
389 }
390 final int resolutionCount = mResolutions.size();
391 parcel.writeInt(resolutionCount);
392 for (int i = 0; i < resolutionCount; i++) {
393 mResolutions.get(i).writeToParcel(parcel);
394 }
395 }
396
397 private void readResolutions(Parcel parcel) {
398 final int resolutionCount = parcel.readInt();
399 if (resolutionCount > 0 && mResolutions == null) {
400 mResolutions = new ArrayList<Resolution>();
401 }
402 for (int i = 0; i < resolutionCount; i++) {
403 mResolutions.add(Resolution.createFromParcel(parcel));
404 }
405 }
406
407 private void writeMargins(Margins margins, Parcel parcel) {
408 if (margins == null) {
409 parcel.writeInt(0);
410 } else {
411 parcel.writeInt(1);
412 margins.writeToParcel(parcel);
413 }
414 }
415
416 private Margins readMargins(Parcel parcel) {
417 return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
418 }
419
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700420 private void readDefaults(Parcel parcel) {
421 final int defaultCount = parcel.readInt();
422 for (int i = 0; i < defaultCount; i++) {
423 mDefaults[i] = parcel.readInt();
424 }
425 }
426
427 private void writeDefaults(Parcel parcel) {
428 final int defaultCount = mDefaults.length;
429 parcel.writeInt(defaultCount);
430 for (int i = 0; i < defaultCount; i++) {
431 parcel.writeInt(mDefaults[i]);
432 }
433 }
434
435 /**
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700436 * Builder for creating of a {@link PrinterCapabilitiesInfo}. This class is
437 * responsible to enforce that all required attributes have at least one
438 * default value. In other words, this class creates only well-formed {@link
439 * PrinterCapabilitiesInfo}s.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700440 * <p>
441 * Look at the individual methods for a reference whether a property is
442 * required or if it is optional.
443 * </p>
444 */
445 public static final class Builder {
446 private final PrinterCapabilitiesInfo mPrototype;
447
448 /**
449 * Creates a new instance.
450 *
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700451 * @param printerId The printer id. Cannot be <code>null</code>.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700452 *
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700453 * @throws IllegalArgumentException If the printer id is <code>null</code>.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700454 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800455 public Builder(@NonNull PrinterId printerId) {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700456 if (printerId == null) {
457 throw new IllegalArgumentException("printerId cannot be null.");
458 }
459 mPrototype = new PrinterCapabilitiesInfo();
460 }
461
462 /**
463 * Adds a supported media size.
464 * <p>
465 * <strong>Required:</strong> Yes
466 * </p>
467 *
468 * @param mediaSize A media size.
469 * @param isDefault Whether this is the default.
470 * @return This builder.
471 * @throws IllegalArgumentException If set as default and there
472 * is already a default.
473 *
474 * @see PrintAttributes.MediaSize
475 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800476 public @NonNull Builder addMediaSize(@NonNull MediaSize mediaSize, boolean isDefault) {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700477 if (mPrototype.mMediaSizes == null) {
478 mPrototype.mMediaSizes = new ArrayList<MediaSize>();
479 }
480 final int insertionIndex = mPrototype.mMediaSizes.size();
481 mPrototype.mMediaSizes.add(mediaSize);
482 if (isDefault) {
483 throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
484 mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex;
485 }
486 return this;
487 }
488
489 /**
490 * Adds a supported resolution.
491 * <p>
492 * <strong>Required:</strong> Yes
493 * </p>
494 *
495 * @param resolution A resolution.
496 * @param isDefault Whether this is the default.
497 * @return This builder.
498 *
499 * @throws IllegalArgumentException If set as default and there
500 * is already a default.
501 *
502 * @see PrintAttributes.Resolution
503 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800504 public @NonNull Builder addResolution(@NonNull Resolution resolution, boolean isDefault) {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700505 if (mPrototype.mResolutions == null) {
506 mPrototype.mResolutions = new ArrayList<Resolution>();
507 }
508 final int insertionIndex = mPrototype.mResolutions.size();
509 mPrototype.mResolutions.add(resolution);
510 if (isDefault) {
511 throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
512 mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex;
513 }
514 return this;
515 }
516
517 /**
Svetoslav651dd4e2013-09-12 14:37:47 -0700518 * Sets the minimal margins. These are the minimal margins
519 * the printer physically supports.
520 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700521 * <p>
Svetoslav651dd4e2013-09-12 14:37:47 -0700522 * <strong>Required:</strong> Yes
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700523 * </p>
524 *
525 * @param margins The margins.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700526 * @return This builder.
527 *
Svetoslav651dd4e2013-09-12 14:37:47 -0700528 * @throws IllegalArgumentException If margins are <code>null</code>.
529 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700530 * @see PrintAttributes.Margins
531 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800532 public @NonNull Builder setMinMargins(@NonNull Margins margins) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700533 if (margins == null) {
534 throw new IllegalArgumentException("margins cannot be null");
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700535 }
536 mPrototype.mMinMargins = margins;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700537 return this;
538 }
539
540 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700541 * Sets the color modes.
542 * <p>
543 * <strong>Required:</strong> Yes
544 * </p>
545 *
546 * @param colorModes The color mode bit mask.
547 * @param defaultColorMode The default color mode.
548 * @return This builder.
Svetoslavb628dd82014-01-02 11:23:44 -0800549 * <p>
550 * <strong>Note:</strong> On platform version 19 (Kitkat) specifying
551 * only PrintAttributes#COLOR_MODE_MONOCHROME leads to a print spooler
552 * crash. Hence, you should declare either both color modes or
553 * PrintAttributes#COLOR_MODE_COLOR.
554 * </p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700555 *
556 * @throws IllegalArgumentException If color modes contains an invalid
557 * mode bit or if the default color mode is invalid.
558 *
559 * @see PrintAttributes#COLOR_MODE_COLOR
560 * @see PrintAttributes#COLOR_MODE_MONOCHROME
561 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800562 public @NonNull Builder setColorModes(@ColorMode int colorModes,
563 @ColorMode int defaultColorMode) {
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -0700564 enforceValidMask(colorModes,
565 (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
Svetoslav948c9a62015-02-02 19:47:04 -0800566 PrintAttributes.enforceValidColorMode(defaultColorMode);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700567 mPrototype.mColorModes = colorModes;
568 mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
569 return this;
570 }
571
572 /**
Svetoslav948c9a62015-02-02 19:47:04 -0800573 * Sets the duplex modes.
574 * <p>
575 * <strong>Required:</strong> No
576 * </p>
577 *
578 * @param duplexModes The duplex mode bit mask.
579 * @param defaultDuplexMode The default duplex mode.
580 * @return This builder.
581 *
582 * @throws IllegalArgumentException If duplex modes contains an invalid
583 * mode bit or if the default duplex mode is invalid.
584 *
585 * @see PrintAttributes#DUPLEX_MODE_NONE
586 * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
587 * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
588 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800589 public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
590 @DuplexMode int defaultDuplexMode) {
Philip P. Moltmanne680a8d2016-03-30 14:18:00 -0700591 enforceValidMask(duplexModes,
592 (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
Svetoslav948c9a62015-02-02 19:47:04 -0800593 PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
594 mPrototype.mDuplexModes = duplexModes;
595 mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
596 return this;
597 }
598
599 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700600 * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700601 * required properties have been specified. See individual methods
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700602 * in this class for reference about required attributes.
Svetoslav948c9a62015-02-02 19:47:04 -0800603 * <p>
604 * <strong>Note:</strong> If you do not add supported duplex modes,
605 * {@link android.print.PrintAttributes#DUPLEX_MODE_NONE} will set
606 * as the only supported mode and also as the default duplex mode.
607 * </p>
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700608 *
609 * @return A new {@link PrinterCapabilitiesInfo}.
610 *
611 * @throws IllegalStateException If a required attribute was not specified.
612 */
Philip P. Moltmannc43639c2015-12-18 13:58:40 -0800613 public @NonNull PrinterCapabilitiesInfo build() {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700614 if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
615 throw new IllegalStateException("No media size specified.");
616 }
617 if (mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] == DEFAULT_UNDEFINED) {
618 throw new IllegalStateException("No default media size specified.");
619 }
620 if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) {
621 throw new IllegalStateException("No resolution specified.");
622 }
623 if (mPrototype.mDefaults[PROPERTY_RESOLUTION] == DEFAULT_UNDEFINED) {
624 throw new IllegalStateException("No default resolution specified.");
625 }
626 if (mPrototype.mColorModes == 0) {
627 throw new IllegalStateException("No color mode specified.");
628 }
629 if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
630 throw new IllegalStateException("No default color mode specified.");
631 }
Svetoslav948c9a62015-02-02 19:47:04 -0800632 if (mPrototype.mDuplexModes == 0) {
633 setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE,
634 PrintAttributes.DUPLEX_MODE_NONE);
635 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700636 if (mPrototype.mMinMargins == null) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700637 throw new IllegalArgumentException("margins cannot be null");
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700638 }
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700639 return mPrototype;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700640 }
641
642 private void throwIfDefaultAlreadySpecified(int propertyIndex) {
643 if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) {
644 throw new IllegalArgumentException("Default already specified.");
645 }
646 }
647 }
648
649 public static final Parcelable.Creator<PrinterCapabilitiesInfo> CREATOR =
650 new Parcelable.Creator<PrinterCapabilitiesInfo>() {
651 @Override
652 public PrinterCapabilitiesInfo createFromParcel(Parcel parcel) {
653 return new PrinterCapabilitiesInfo(parcel);
654 }
655
656 @Override
657 public PrinterCapabilitiesInfo[] newArray(int size) {
658 return new PrinterCapabilitiesInfo[size];
659 }
660 };
661}