blob: b615600d33ae83319f81e420f24009f715bffab2 [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;
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -070027import java.util.Collections;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070028import java.util.List;
29
30/**
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -070031 * This class represents the capabilities of a printer. Instances
32 * of this class are created by a print service to report the
33 * capabilities of a printer it manages. The capabilities of a
34 * printer specify how it can print content. For example, what
35 * are the media sizes supported by the printer, what are the
36 * minimal margins of the printer based on its technical design,
37 * etc.
Svetoslav Ganov798bed62013-08-11 12:29:39 -070038 */
39public final class PrinterCapabilitiesInfo implements Parcelable {
40 /**
41 * Undefined default value.
42 *
43 * @hide
44 */
45 public static final int DEFAULT_UNDEFINED = -1;
46
47 private static final int PROPERTY_MEDIA_SIZE = 0;
48 private static final int PROPERTY_RESOLUTION = 1;
Svetoslav773f54d2013-09-03 14:01:43 -070049 private static final int PROPERTY_COLOR_MODE = 2;
50 private static final int PROPERTY_COUNT = 3;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070051
52 private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
53
54 private Margins mMinMargins = DEFAULT_MARGINS;
55 private List<MediaSize> mMediaSizes;
56 private List<Resolution> mResolutions;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070057
Svetoslav Ganov798bed62013-08-11 12:29:39 -070058 private int mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -070059
60 private final int[] mDefaults = new int[PROPERTY_COUNT];
Svetoslav Ganov798bed62013-08-11 12:29:39 -070061
62 /**
63 * @hide
64 */
65 public PrinterCapabilitiesInfo() {
66 Arrays.fill(mDefaults, DEFAULT_UNDEFINED);
67 }
68
69 /**
70 * @hide
71 */
72 public PrinterCapabilitiesInfo(PrinterCapabilitiesInfo prototype) {
73 copyFrom(prototype);
74 }
75
76 /**
77 * @hide
78 */
79 public void copyFrom(PrinterCapabilitiesInfo other) {
Svetoslav651dd4e2013-09-12 14:37:47 -070080 if (this == other) {
81 return;
82 }
83
Svetoslav Ganov798bed62013-08-11 12:29:39 -070084 mMinMargins = other.mMinMargins;
85
86 if (other.mMediaSizes != null) {
87 if (mMediaSizes != null) {
88 mMediaSizes.clear();
89 mMediaSizes.addAll(other.mMediaSizes);
90 } else {
91 mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes);
92 }
93 } else {
94 mMediaSizes = null;
95 }
96
97 if (other.mResolutions != null) {
98 if (mResolutions != null) {
99 mResolutions.clear();
100 mResolutions.addAll(other.mResolutions);
101 } else {
102 mResolutions = new ArrayList<Resolution>(other.mResolutions);
103 }
104 } else {
105 mResolutions = null;
106 }
107
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700108 mColorModes = other.mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700109
110 final int defaultCount = other.mDefaults.length;
111 for (int i = 0; i < defaultCount; i++) {
112 mDefaults[i] = other.mDefaults[i];
113 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700114 }
115
116 /**
117 * Gets the supported media sizes.
118 *
119 * @return The media sizes.
120 */
121 public List<MediaSize> getMediaSizes() {
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700122 return Collections.unmodifiableList(mMediaSizes);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700123 }
124
125 /**
126 * Gets the supported resolutions.
127 *
128 * @return The resolutions.
129 */
130 public List<Resolution> getResolutions() {
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700131 return Collections.unmodifiableList(mResolutions);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700132 }
133
134 /**
Svetoslav651dd4e2013-09-12 14:37:47 -0700135 * Gets the minimal margins. These are the minimal margins
136 * the printer physically supports.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700137 *
138 * @return The minimal margins.
139 */
140 public Margins getMinMargins() {
141 return mMinMargins;
142 }
143
144 /**
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700145 * Gets the bit mask of supported color modes.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700146 *
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700147 * @return The bit mask of supported color modes.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700148 *
149 * @see PrintAttributes#COLOR_MODE_COLOR
150 * @see PrintAttributes#COLOR_MODE_MONOCHROME
151 */
152 public int getColorModes() {
153 return mColorModes;
154 }
155
156 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700157 * Gets the default print attributes.
158 *
Svetoslav651dd4e2013-09-12 14:37:47 -0700159 * @return The default attributes.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700160 */
Svetoslav651dd4e2013-09-12 14:37:47 -0700161 public PrintAttributes getDefaults() {
162 PrintAttributes.Builder builder = new PrintAttributes.Builder();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700163
Svetoslav651dd4e2013-09-12 14:37:47 -0700164 builder.setMinMargins(mMinMargins);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700165
166 final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
167 if (mediaSizeIndex >= 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700168 builder.setMediaSize(mMediaSizes.get(mediaSizeIndex));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700169 }
170
171 final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
172 if (resolutionIndex >= 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700173 builder.setResolution(mResolutions.get(resolutionIndex));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700174 }
175
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700176 final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
177 if (colorMode > 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700178 builder.setColorMode(colorMode);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700179 }
Svetoslav651dd4e2013-09-12 14:37:47 -0700180
181 return builder.build();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700182 }
183
184 private PrinterCapabilitiesInfo(Parcel parcel) {
185 mMinMargins = readMargins(parcel);
186 readMediaSizes(parcel);
187 readResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700188
189 mColorModes = parcel.readInt();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700190
191 readDefaults(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700192 }
193
194 @Override
195 public int describeContents() {
196 return 0;
197 }
198
199 @Override
200 public void writeToParcel(Parcel parcel, int flags) {
201 writeMargins(mMinMargins, parcel);
202 writeMediaSizes(parcel);
203 writeResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700204
205 parcel.writeInt(mColorModes);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700206
207 writeDefaults(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700208 }
209
210 @Override
211 public int hashCode() {
212 final int prime = 31;
213 int result = 1;
214 result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
215 result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
216 result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700217 result = prime * result + mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700218 result = prime * result + Arrays.hashCode(mDefaults);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700219 return result;
220 }
221
222 @Override
223 public boolean equals(Object obj) {
224 if (this == obj) {
225 return true;
226 }
227 if (obj == null) {
228 return false;
229 }
230 if (getClass() != obj.getClass()) {
231 return false;
232 }
233 PrinterCapabilitiesInfo other = (PrinterCapabilitiesInfo) obj;
234 if (mMinMargins == null) {
235 if (other.mMinMargins != null) {
236 return false;
237 }
238 } else if (!mMinMargins.equals(other.mMinMargins)) {
239 return false;
240 }
241 if (mMediaSizes == null) {
242 if (other.mMediaSizes != null) {
243 return false;
244 }
245 } else if (!mMediaSizes.equals(other.mMediaSizes)) {
246 return false;
247 }
248 if (mResolutions == null) {
249 if (other.mResolutions != null) {
250 return false;
251 }
252 } else if (!mResolutions.equals(other.mResolutions)) {
253 return false;
254 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700255 if (mColorModes != other.mColorModes) {
256 return false;
257 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700258 if (!Arrays.equals(mDefaults, other.mDefaults)) {
259 return false;
260 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700261 return true;
262 }
263
264 @Override
265 public String toString() {
266 StringBuilder builder = new StringBuilder();
267 builder.append("PrinterInfo{");
268 builder.append("minMargins=").append(mMinMargins);
269 builder.append(", mediaSizes=").append(mMediaSizes);
270 builder.append(", resolutions=").append(mResolutions);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700271 builder.append(", colorModes=").append(colorModesToString());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700272 builder.append("\"}");
273 return builder.toString();
274 }
275
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700276 private String colorModesToString() {
277 StringBuilder builder = new StringBuilder();
278 builder.append('[');
279 int colorModes = mColorModes;
280 while (colorModes != 0) {
281 final int colorMode = 1 << Integer.numberOfTrailingZeros(colorModes);
282 colorModes &= ~colorMode;
Svetoslav651dd4e2013-09-12 14:37:47 -0700283 if (builder.length() > 1) {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700284 builder.append(", ");
285 }
286 builder.append(PrintAttributes.colorModeToString(colorMode));
287 }
288 builder.append(']');
289 return builder.toString();
290 }
291
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700292 private void writeMediaSizes(Parcel parcel) {
293 if (mMediaSizes == null) {
294 parcel.writeInt(0);
295 return;
296 }
297 final int mediaSizeCount = mMediaSizes.size();
298 parcel.writeInt(mediaSizeCount);
299 for (int i = 0; i < mediaSizeCount; i++) {
300 mMediaSizes.get(i).writeToParcel(parcel);
301 }
302 }
303
304 private void readMediaSizes(Parcel parcel) {
305 final int mediaSizeCount = parcel.readInt();
306 if (mediaSizeCount > 0 && mMediaSizes == null) {
307 mMediaSizes = new ArrayList<MediaSize>();
308 }
309 for (int i = 0; i < mediaSizeCount; i++) {
310 mMediaSizes.add(MediaSize.createFromParcel(parcel));
311 }
312 }
313
314 private void writeResolutions(Parcel parcel) {
315 if (mResolutions == null) {
316 parcel.writeInt(0);
317 return;
318 }
319 final int resolutionCount = mResolutions.size();
320 parcel.writeInt(resolutionCount);
321 for (int i = 0; i < resolutionCount; i++) {
322 mResolutions.get(i).writeToParcel(parcel);
323 }
324 }
325
326 private void readResolutions(Parcel parcel) {
327 final int resolutionCount = parcel.readInt();
328 if (resolutionCount > 0 && mResolutions == null) {
329 mResolutions = new ArrayList<Resolution>();
330 }
331 for (int i = 0; i < resolutionCount; i++) {
332 mResolutions.add(Resolution.createFromParcel(parcel));
333 }
334 }
335
336 private void writeMargins(Margins margins, Parcel parcel) {
337 if (margins == null) {
338 parcel.writeInt(0);
339 } else {
340 parcel.writeInt(1);
341 margins.writeToParcel(parcel);
342 }
343 }
344
345 private Margins readMargins(Parcel parcel) {
346 return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
347 }
348
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700349 private void readDefaults(Parcel parcel) {
350 final int defaultCount = parcel.readInt();
351 for (int i = 0; i < defaultCount; i++) {
352 mDefaults[i] = parcel.readInt();
353 }
354 }
355
356 private void writeDefaults(Parcel parcel) {
357 final int defaultCount = mDefaults.length;
358 parcel.writeInt(defaultCount);
359 for (int i = 0; i < defaultCount; i++) {
360 parcel.writeInt(mDefaults[i]);
361 }
362 }
363
364 /**
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700365 * Builder for creating of a {@link PrinterCapabilitiesInfo}. This class is
366 * responsible to enforce that all required attributes have at least one
367 * default value. In other words, this class creates only well-formed {@link
368 * PrinterCapabilitiesInfo}s.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700369 * <p>
370 * Look at the individual methods for a reference whether a property is
371 * required or if it is optional.
372 * </p>
373 */
374 public static final class Builder {
375 private final PrinterCapabilitiesInfo mPrototype;
376
377 /**
378 * Creates a new instance.
379 *
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700380 * @param printerId The printer id. Cannot be <code>null</code>.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700381 *
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700382 * @throws IllegalArgumentException If the printer id is <code>null</code>.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700383 */
384 public Builder(PrinterId printerId) {
385 if (printerId == null) {
386 throw new IllegalArgumentException("printerId cannot be null.");
387 }
388 mPrototype = new PrinterCapabilitiesInfo();
389 }
390
391 /**
392 * Adds a supported media size.
393 * <p>
394 * <strong>Required:</strong> Yes
395 * </p>
396 *
397 * @param mediaSize A media size.
398 * @param isDefault Whether this is the default.
399 * @return This builder.
400 * @throws IllegalArgumentException If set as default and there
401 * is already a default.
402 *
403 * @see PrintAttributes.MediaSize
404 */
405 public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
406 if (mPrototype.mMediaSizes == null) {
407 mPrototype.mMediaSizes = new ArrayList<MediaSize>();
408 }
409 final int insertionIndex = mPrototype.mMediaSizes.size();
410 mPrototype.mMediaSizes.add(mediaSize);
411 if (isDefault) {
412 throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
413 mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex;
414 }
415 return this;
416 }
417
418 /**
419 * Adds a supported resolution.
420 * <p>
421 * <strong>Required:</strong> Yes
422 * </p>
423 *
424 * @param resolution A resolution.
425 * @param isDefault Whether this is the default.
426 * @return This builder.
427 *
428 * @throws IllegalArgumentException If set as default and there
429 * is already a default.
430 *
431 * @see PrintAttributes.Resolution
432 */
433 public Builder addResolution(Resolution resolution, boolean isDefault) {
434 if (mPrototype.mResolutions == null) {
435 mPrototype.mResolutions = new ArrayList<Resolution>();
436 }
437 final int insertionIndex = mPrototype.mResolutions.size();
438 mPrototype.mResolutions.add(resolution);
439 if (isDefault) {
440 throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
441 mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex;
442 }
443 return this;
444 }
445
446 /**
Svetoslav651dd4e2013-09-12 14:37:47 -0700447 * Sets the minimal margins. These are the minimal margins
448 * the printer physically supports.
449 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700450 * <p>
Svetoslav651dd4e2013-09-12 14:37:47 -0700451 * <strong>Required:</strong> Yes
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700452 * </p>
453 *
454 * @param margins The margins.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700455 * @return This builder.
456 *
Svetoslav651dd4e2013-09-12 14:37:47 -0700457 * @throws IllegalArgumentException If margins are <code>null</code>.
458 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700459 * @see PrintAttributes.Margins
460 */
Svetoslav651dd4e2013-09-12 14:37:47 -0700461 public Builder setMinMargins(Margins margins) {
462 if (margins == null) {
463 throw new IllegalArgumentException("margins cannot be null");
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700464 }
465 mPrototype.mMinMargins = margins;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700466 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
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700503 * required properties have been specified. See individual methods
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700504 * 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 */
Svetoslav651dd4e2013-09-12 14:37:47 -0700510 public PrinterCapabilitiesInfo build() {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700511 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) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700530 throw new IllegalArgumentException("margins cannot be null");
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700531 }
Svetoslav Ganov4d4c66d2013-10-24 18:04:39 -0700532 return mPrototype;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700533 }
534
535 private void throwIfDefaultAlreadySpecified(int propertyIndex) {
536 if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) {
537 throw new IllegalArgumentException("Default already specified.");
538 }
539 }
540 }
541
542 public static final Parcelable.Creator<PrinterCapabilitiesInfo> CREATOR =
543 new Parcelable.Creator<PrinterCapabilitiesInfo>() {
544 @Override
545 public PrinterCapabilitiesInfo createFromParcel(Parcel parcel) {
546 return new PrinterCapabilitiesInfo(parcel);
547 }
548
549 @Override
550 public PrinterCapabilitiesInfo[] newArray(int size) {
551 return new PrinterCapabilitiesInfo[size];
552 }
553 };
554}
555