blob: ea44c876672a084a15429986240f2bd1fbdebd78 [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;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070024
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.List;
28
29/**
30 * This class represents the capabilities of a printer.
31 */
32public final class PrinterCapabilitiesInfo implements Parcelable {
33 /**
34 * Undefined default value.
35 *
36 * @hide
37 */
38 public static final int DEFAULT_UNDEFINED = -1;
39
40 private static final int PROPERTY_MEDIA_SIZE = 0;
41 private static final int PROPERTY_RESOLUTION = 1;
Svetoslav773f54d2013-09-03 14:01:43 -070042 private static final int PROPERTY_COLOR_MODE = 2;
43 private static final int PROPERTY_COUNT = 3;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070044
45 private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
46
47 private Margins mMinMargins = DEFAULT_MARGINS;
48 private List<MediaSize> mMediaSizes;
49 private List<Resolution> mResolutions;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070050
Svetoslav Ganov798bed62013-08-11 12:29:39 -070051 private int mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070052
53 private final int[] mDefaults = new int[PROPERTY_COUNT];
54 private Margins mDefaultMargins = DEFAULT_MARGINS;
55
56 /**
57 * @hide
58 */
59 public PrinterCapabilitiesInfo() {
60 Arrays.fill(mDefaults, DEFAULT_UNDEFINED);
61 }
62
63 /**
64 * @hide
65 */
66 public PrinterCapabilitiesInfo(PrinterCapabilitiesInfo prototype) {
67 copyFrom(prototype);
68 }
69
70 /**
71 * @hide
72 */
73 public void copyFrom(PrinterCapabilitiesInfo other) {
74 mMinMargins = other.mMinMargins;
75
76 if (other.mMediaSizes != null) {
77 if (mMediaSizes != null) {
78 mMediaSizes.clear();
79 mMediaSizes.addAll(other.mMediaSizes);
80 } else {
81 mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes);
82 }
83 } else {
84 mMediaSizes = null;
85 }
86
87 if (other.mResolutions != null) {
88 if (mResolutions != null) {
89 mResolutions.clear();
90 mResolutions.addAll(other.mResolutions);
91 } else {
92 mResolutions = new ArrayList<Resolution>(other.mResolutions);
93 }
94 } else {
95 mResolutions = null;
96 }
97
Svetoslav Ganov798bed62013-08-11 12:29:39 -070098 mColorModes = other.mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070099
100 final int defaultCount = other.mDefaults.length;
101 for (int i = 0; i < defaultCount; i++) {
102 mDefaults[i] = other.mDefaults[i];
103 }
104
105 mDefaultMargins = other.mDefaultMargins;
106 }
107
108 /**
109 * Gets the supported media sizes.
110 *
111 * @return The media sizes.
112 */
113 public List<MediaSize> getMediaSizes() {
114 return mMediaSizes;
115 }
116
117 /**
118 * Gets the supported resolutions.
119 *
120 * @return The resolutions.
121 */
122 public List<Resolution> getResolutions() {
123 return mResolutions;
124 }
125
126 /**
127 * Gets the minimal supported margins.
128 *
129 * @return The minimal margins.
130 */
131 public Margins getMinMargins() {
132 return mMinMargins;
133 }
134
135 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700136 * Gets the supported color modes.
137 *
138 * @return The color modes.
139 *
140 * @see PrintAttributes#COLOR_MODE_COLOR
141 * @see PrintAttributes#COLOR_MODE_MONOCHROME
142 */
143 public int getColorModes() {
144 return mColorModes;
145 }
146
147 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700148 * Gets the default print attributes.
149 *
150 * @param outAttributes The attributes to populated.
151 */
152 public void getDefaults(PrintAttributes outAttributes) {
153 outAttributes.clear();
154
155 outAttributes.setMargins(mDefaultMargins);
156
157 final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
158 if (mediaSizeIndex >= 0) {
159 outAttributes.setMediaSize(mMediaSizes.get(mediaSizeIndex));
160 }
161
162 final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
163 if (resolutionIndex >= 0) {
164 outAttributes.setResolution(mResolutions.get(resolutionIndex));
165 }
166
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700167 final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
168 if (colorMode > 0) {
169 outAttributes.setColorMode(colorMode);
170 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700171 }
172
173 private PrinterCapabilitiesInfo(Parcel parcel) {
174 mMinMargins = readMargins(parcel);
175 readMediaSizes(parcel);
176 readResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700177
178 mColorModes = parcel.readInt();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700179
180 readDefaults(parcel);
181 mDefaultMargins = readMargins(parcel);
182 }
183
184 @Override
185 public int describeContents() {
186 return 0;
187 }
188
189 @Override
190 public void writeToParcel(Parcel parcel, int flags) {
191 writeMargins(mMinMargins, parcel);
192 writeMediaSizes(parcel);
193 writeResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700194
195 parcel.writeInt(mColorModes);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700196
197 writeDefaults(parcel);
198 writeMargins(mDefaultMargins, parcel);
199 }
200
201 @Override
202 public int hashCode() {
203 final int prime = 31;
204 int result = 1;
205 result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
206 result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
207 result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700208 result = prime * result + mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700209 result = prime * result + Arrays.hashCode(mDefaults);
210 result = prime * result + ((mDefaultMargins == null) ? 0 : mDefaultMargins.hashCode());
211 return result;
212 }
213
214 @Override
215 public boolean equals(Object obj) {
216 if (this == obj) {
217 return true;
218 }
219 if (obj == null) {
220 return false;
221 }
222 if (getClass() != obj.getClass()) {
223 return false;
224 }
225 PrinterCapabilitiesInfo other = (PrinterCapabilitiesInfo) obj;
226 if (mMinMargins == null) {
227 if (other.mMinMargins != null) {
228 return false;
229 }
230 } else if (!mMinMargins.equals(other.mMinMargins)) {
231 return false;
232 }
233 if (mMediaSizes == null) {
234 if (other.mMediaSizes != null) {
235 return false;
236 }
237 } else if (!mMediaSizes.equals(other.mMediaSizes)) {
238 return false;
239 }
240 if (mResolutions == null) {
241 if (other.mResolutions != null) {
242 return false;
243 }
244 } else if (!mResolutions.equals(other.mResolutions)) {
245 return false;
246 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700247 if (mColorModes != other.mColorModes) {
248 return false;
249 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700250 if (!Arrays.equals(mDefaults, other.mDefaults)) {
251 return false;
252 }
253 if (mDefaultMargins == null) {
254 if (other.mDefaultMargins != null) {
255 return false;
256 }
257 } else if (!mDefaultMargins.equals(other.mDefaultMargins)) {
258 return false;
259 }
260 return true;
261 }
262
263 @Override
264 public String toString() {
265 StringBuilder builder = new StringBuilder();
266 builder.append("PrinterInfo{");
267 builder.append("minMargins=").append(mMinMargins);
268 builder.append(", mediaSizes=").append(mMediaSizes);
269 builder.append(", resolutions=").append(mResolutions);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700270 builder.append(", colorModes=").append(colorModesToString());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700271 builder.append("\"}");
272 return builder.toString();
273 }
274
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700275 private String colorModesToString() {
276 StringBuilder builder = new StringBuilder();
277 builder.append('[');
278 int colorModes = mColorModes;
279 while (colorModes != 0) {
280 final int colorMode = 1 << Integer.numberOfTrailingZeros(colorModes);
281 colorModes &= ~colorMode;
282 if (builder.length() > 0) {
283 builder.append(", ");
284 }
285 builder.append(PrintAttributes.colorModeToString(colorMode));
286 }
287 builder.append(']');
288 return builder.toString();
289 }
290
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700291 private void writeMediaSizes(Parcel parcel) {
292 if (mMediaSizes == null) {
293 parcel.writeInt(0);
294 return;
295 }
296 final int mediaSizeCount = mMediaSizes.size();
297 parcel.writeInt(mediaSizeCount);
298 for (int i = 0; i < mediaSizeCount; i++) {
299 mMediaSizes.get(i).writeToParcel(parcel);
300 }
301 }
302
303 private void readMediaSizes(Parcel parcel) {
304 final int mediaSizeCount = parcel.readInt();
305 if (mediaSizeCount > 0 && mMediaSizes == null) {
306 mMediaSizes = new ArrayList<MediaSize>();
307 }
308 for (int i = 0; i < mediaSizeCount; i++) {
309 mMediaSizes.add(MediaSize.createFromParcel(parcel));
310 }
311 }
312
313 private void writeResolutions(Parcel parcel) {
314 if (mResolutions == null) {
315 parcel.writeInt(0);
316 return;
317 }
318 final int resolutionCount = mResolutions.size();
319 parcel.writeInt(resolutionCount);
320 for (int i = 0; i < resolutionCount; i++) {
321 mResolutions.get(i).writeToParcel(parcel);
322 }
323 }
324
325 private void readResolutions(Parcel parcel) {
326 final int resolutionCount = parcel.readInt();
327 if (resolutionCount > 0 && mResolutions == null) {
328 mResolutions = new ArrayList<Resolution>();
329 }
330 for (int i = 0; i < resolutionCount; i++) {
331 mResolutions.add(Resolution.createFromParcel(parcel));
332 }
333 }
334
335 private void writeMargins(Margins margins, Parcel parcel) {
336 if (margins == null) {
337 parcel.writeInt(0);
338 } else {
339 parcel.writeInt(1);
340 margins.writeToParcel(parcel);
341 }
342 }
343
344 private Margins readMargins(Parcel parcel) {
345 return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
346 }
347
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700348 private void readDefaults(Parcel parcel) {
349 final int defaultCount = parcel.readInt();
350 for (int i = 0; i < defaultCount; i++) {
351 mDefaults[i] = parcel.readInt();
352 }
353 }
354
355 private void writeDefaults(Parcel parcel) {
356 final int defaultCount = mDefaults.length;
357 parcel.writeInt(defaultCount);
358 for (int i = 0; i < defaultCount; i++) {
359 parcel.writeInt(mDefaults[i]);
360 }
361 }
362
363 /**
364 * Builder for creating of a {@link PrinterInfo}. This class is responsible
365 * to enforce that all required attributes have at least one default value.
366 * In other words, this class creates only well-formed {@link PrinterInfo}s.
367 * <p>
368 * Look at the individual methods for a reference whether a property is
369 * required or if it is optional.
370 * </p>
371 */
372 public static final class Builder {
373 private final PrinterCapabilitiesInfo mPrototype;
374
375 /**
376 * Creates a new instance.
377 *
378 * @param printerId The printer id. Cannot be null.
379 *
380 * @throws IllegalArgumentException If the printer id is null.
381 */
382 public Builder(PrinterId printerId) {
383 if (printerId == null) {
384 throw new IllegalArgumentException("printerId cannot be null.");
385 }
386 mPrototype = new PrinterCapabilitiesInfo();
387 }
388
389 /**
390 * Adds a supported media size.
391 * <p>
392 * <strong>Required:</strong> Yes
393 * </p>
394 *
395 * @param mediaSize A media size.
396 * @param isDefault Whether this is the default.
397 * @return This builder.
398 * @throws IllegalArgumentException If set as default and there
399 * is already a default.
400 *
401 * @see PrintAttributes.MediaSize
402 */
403 public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
404 if (mPrototype.mMediaSizes == null) {
405 mPrototype.mMediaSizes = new ArrayList<MediaSize>();
406 }
407 final int insertionIndex = mPrototype.mMediaSizes.size();
408 mPrototype.mMediaSizes.add(mediaSize);
409 if (isDefault) {
410 throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
411 mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex;
412 }
413 return this;
414 }
415
416 /**
417 * Adds a supported resolution.
418 * <p>
419 * <strong>Required:</strong> Yes
420 * </p>
421 *
422 * @param resolution A resolution.
423 * @param isDefault Whether this is the default.
424 * @return This builder.
425 *
426 * @throws IllegalArgumentException If set as default and there
427 * is already a default.
428 *
429 * @see PrintAttributes.Resolution
430 */
431 public Builder addResolution(Resolution resolution, boolean isDefault) {
432 if (mPrototype.mResolutions == null) {
433 mPrototype.mResolutions = new ArrayList<Resolution>();
434 }
435 final int insertionIndex = mPrototype.mResolutions.size();
436 mPrototype.mResolutions.add(resolution);
437 if (isDefault) {
438 throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
439 mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex;
440 }
441 return this;
442 }
443
444 /**
445 * Sets the minimal margins.
446 * <p>
447 * <strong>Required:</strong> No
448 * </p>
449 *
450 * @param margins The margins.
451 * @param defaultMargins The default margins.
452 * @return This builder.
453 *
454 * @see PrintAttributes.Margins
455 */
456 public Builder setMinMargins(Margins margins, Margins defaultMargins) {
457 if (margins.getLeftMils() > defaultMargins.getLeftMils()
458 || margins.getTopMils() > defaultMargins.getTopMils()
459 || margins.getRightMils() < defaultMargins.getRightMils()
460 || margins.getBottomMils() < defaultMargins.getBottomMils()) {
461 throw new IllegalArgumentException("Default margins"
462 + " cannot be outside of the min margins.");
463 }
464 mPrototype.mMinMargins = margins;
465 mPrototype.mDefaultMargins = defaultMargins;
466 return this;
467 }
468
469 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700470 * Sets the color modes.
471 * <p>
472 * <strong>Required:</strong> Yes
473 * </p>
474 *
475 * @param colorModes The color mode bit mask.
476 * @param defaultColorMode The default color mode.
477 * @return This builder.
478 *
479 * @throws IllegalArgumentException If color modes contains an invalid
480 * mode bit or if the default color mode is invalid.
481 *
482 * @see PrintAttributes#COLOR_MODE_COLOR
483 * @see PrintAttributes#COLOR_MODE_MONOCHROME
484 */
485 public Builder setColorModes(int colorModes, int defaultColorMode) {
486 int currentModes = colorModes;
487 while (currentModes > 0) {
488 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
489 currentModes &= ~currentMode;
490 PrintAttributes.enforceValidColorMode(currentMode);
491 }
492 if ((colorModes & defaultColorMode) == 0) {
493 throw new IllegalArgumentException("Default color mode not in color modes.");
494 }
495 PrintAttributes.enforceValidColorMode(colorModes);
496 mPrototype.mColorModes = colorModes;
497 mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
498 return this;
499 }
500
501 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700502 * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
503 * required properties have need specified. See individual methods
504 * in this class for reference about required attributes.
505 *
506 * @return A new {@link PrinterCapabilitiesInfo}.
507 *
508 * @throws IllegalStateException If a required attribute was not specified.
509 */
510 public PrinterCapabilitiesInfo create() {
511 if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
512 throw new IllegalStateException("No media size specified.");
513 }
514 if (mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] == DEFAULT_UNDEFINED) {
515 throw new IllegalStateException("No default media size specified.");
516 }
517 if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) {
518 throw new IllegalStateException("No resolution specified.");
519 }
520 if (mPrototype.mDefaults[PROPERTY_RESOLUTION] == DEFAULT_UNDEFINED) {
521 throw new IllegalStateException("No default resolution specified.");
522 }
523 if (mPrototype.mColorModes == 0) {
524 throw new IllegalStateException("No color mode specified.");
525 }
526 if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
527 throw new IllegalStateException("No default color mode specified.");
528 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700529 if (mPrototype.mMinMargins == null) {
530 mPrototype.mMinMargins = new Margins(0, 0, 0, 0);
531 }
532 if (mPrototype.mDefaultMargins == null) {
533 mPrototype.mDefaultMargins = mPrototype.mMinMargins;
534 }
535 return new PrinterCapabilitiesInfo(mPrototype);
536 }
537
538 private void throwIfDefaultAlreadySpecified(int propertyIndex) {
539 if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) {
540 throw new IllegalArgumentException("Default already specified.");
541 }
542 }
543 }
544
545 public static final Parcelable.Creator<PrinterCapabilitiesInfo> CREATOR =
546 new Parcelable.Creator<PrinterCapabilitiesInfo>() {
547 @Override
548 public PrinterCapabilitiesInfo createFromParcel(Parcel parcel) {
549 return new PrinterCapabilitiesInfo(parcel);
550 }
551
552 @Override
553 public PrinterCapabilitiesInfo[] newArray(int size) {
554 return new PrinterCapabilitiesInfo[size];
555 }
556 };
557}
558