blob: df51ec10fb7900bfdd6cf776f30772584d1cb23b [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];
Svetoslav Ganov798bed62013-08-11 12:29:39 -070054
55 /**
56 * @hide
57 */
58 public PrinterCapabilitiesInfo() {
59 Arrays.fill(mDefaults, DEFAULT_UNDEFINED);
60 }
61
62 /**
63 * @hide
64 */
65 public PrinterCapabilitiesInfo(PrinterCapabilitiesInfo prototype) {
66 copyFrom(prototype);
67 }
68
69 /**
70 * @hide
71 */
72 public void copyFrom(PrinterCapabilitiesInfo other) {
Svetoslav651dd4e2013-09-12 14:37:47 -070073 if (this == other) {
74 return;
75 }
76
Svetoslav Ganov798bed62013-08-11 12:29:39 -070077 mMinMargins = other.mMinMargins;
78
79 if (other.mMediaSizes != null) {
80 if (mMediaSizes != null) {
81 mMediaSizes.clear();
82 mMediaSizes.addAll(other.mMediaSizes);
83 } else {
84 mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes);
85 }
86 } else {
87 mMediaSizes = null;
88 }
89
90 if (other.mResolutions != null) {
91 if (mResolutions != null) {
92 mResolutions.clear();
93 mResolutions.addAll(other.mResolutions);
94 } else {
95 mResolutions = new ArrayList<Resolution>(other.mResolutions);
96 }
97 } else {
98 mResolutions = null;
99 }
100
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700101 mColorModes = other.mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700102
103 final int defaultCount = other.mDefaults.length;
104 for (int i = 0; i < defaultCount; i++) {
105 mDefaults[i] = other.mDefaults[i];
106 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700107 }
108
109 /**
110 * Gets the supported media sizes.
111 *
112 * @return The media sizes.
113 */
114 public List<MediaSize> getMediaSizes() {
115 return mMediaSizes;
116 }
117
118 /**
119 * Gets the supported resolutions.
120 *
121 * @return The resolutions.
122 */
123 public List<Resolution> getResolutions() {
124 return mResolutions;
125 }
126
127 /**
Svetoslav651dd4e2013-09-12 14:37:47 -0700128 * Gets the minimal margins. These are the minimal margins
129 * the printer physically supports.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700130 *
131 * @return The minimal margins.
132 */
133 public Margins getMinMargins() {
134 return mMinMargins;
135 }
136
137 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700138 * Gets the supported color modes.
139 *
140 * @return The color modes.
141 *
142 * @see PrintAttributes#COLOR_MODE_COLOR
143 * @see PrintAttributes#COLOR_MODE_MONOCHROME
144 */
145 public int getColorModes() {
146 return mColorModes;
147 }
148
149 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700150 * Gets the default print attributes.
151 *
Svetoslav651dd4e2013-09-12 14:37:47 -0700152 * @return The default attributes.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700153 */
Svetoslav651dd4e2013-09-12 14:37:47 -0700154 public PrintAttributes getDefaults() {
155 PrintAttributes.Builder builder = new PrintAttributes.Builder();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700156
Svetoslav651dd4e2013-09-12 14:37:47 -0700157 builder.setMinMargins(mMinMargins);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700158
159 final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
160 if (mediaSizeIndex >= 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700161 builder.setMediaSize(mMediaSizes.get(mediaSizeIndex));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700162 }
163
164 final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
165 if (resolutionIndex >= 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700166 builder.setResolution(mResolutions.get(resolutionIndex));
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700167 }
168
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700169 final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
170 if (colorMode > 0) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700171 builder.setColorMode(colorMode);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700172 }
Svetoslav651dd4e2013-09-12 14:37:47 -0700173
174 return builder.build();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700175 }
176
177 private PrinterCapabilitiesInfo(Parcel parcel) {
178 mMinMargins = readMargins(parcel);
179 readMediaSizes(parcel);
180 readResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700181
182 mColorModes = parcel.readInt();
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700183
184 readDefaults(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700185 }
186
187 @Override
188 public int describeContents() {
189 return 0;
190 }
191
192 @Override
193 public void writeToParcel(Parcel parcel, int flags) {
194 writeMargins(mMinMargins, parcel);
195 writeMediaSizes(parcel);
196 writeResolutions(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700197
198 parcel.writeInt(mColorModes);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700199
200 writeDefaults(parcel);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700201 }
202
203 @Override
204 public int hashCode() {
205 final int prime = 31;
206 int result = 1;
207 result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
208 result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
209 result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700210 result = prime * result + mColorModes;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700211 result = prime * result + Arrays.hashCode(mDefaults);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700212 return result;
213 }
214
215 @Override
216 public boolean equals(Object obj) {
217 if (this == obj) {
218 return true;
219 }
220 if (obj == null) {
221 return false;
222 }
223 if (getClass() != obj.getClass()) {
224 return false;
225 }
226 PrinterCapabilitiesInfo other = (PrinterCapabilitiesInfo) obj;
227 if (mMinMargins == null) {
228 if (other.mMinMargins != null) {
229 return false;
230 }
231 } else if (!mMinMargins.equals(other.mMinMargins)) {
232 return false;
233 }
234 if (mMediaSizes == null) {
235 if (other.mMediaSizes != null) {
236 return false;
237 }
238 } else if (!mMediaSizes.equals(other.mMediaSizes)) {
239 return false;
240 }
241 if (mResolutions == null) {
242 if (other.mResolutions != null) {
243 return false;
244 }
245 } else if (!mResolutions.equals(other.mResolutions)) {
246 return false;
247 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700248 if (mColorModes != other.mColorModes) {
249 return false;
250 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700251 if (!Arrays.equals(mDefaults, other.mDefaults)) {
252 return false;
253 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700254 return true;
255 }
256
257 @Override
258 public String toString() {
259 StringBuilder builder = new StringBuilder();
260 builder.append("PrinterInfo{");
261 builder.append("minMargins=").append(mMinMargins);
262 builder.append(", mediaSizes=").append(mMediaSizes);
263 builder.append(", resolutions=").append(mResolutions);
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700264 builder.append(", colorModes=").append(colorModesToString());
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700265 builder.append("\"}");
266 return builder.toString();
267 }
268
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700269 private String colorModesToString() {
270 StringBuilder builder = new StringBuilder();
271 builder.append('[');
272 int colorModes = mColorModes;
273 while (colorModes != 0) {
274 final int colorMode = 1 << Integer.numberOfTrailingZeros(colorModes);
275 colorModes &= ~colorMode;
Svetoslav651dd4e2013-09-12 14:37:47 -0700276 if (builder.length() > 1) {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700277 builder.append(", ");
278 }
279 builder.append(PrintAttributes.colorModeToString(colorMode));
280 }
281 builder.append(']');
282 return builder.toString();
283 }
284
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700285 private void writeMediaSizes(Parcel parcel) {
286 if (mMediaSizes == null) {
287 parcel.writeInt(0);
288 return;
289 }
290 final int mediaSizeCount = mMediaSizes.size();
291 parcel.writeInt(mediaSizeCount);
292 for (int i = 0; i < mediaSizeCount; i++) {
293 mMediaSizes.get(i).writeToParcel(parcel);
294 }
295 }
296
297 private void readMediaSizes(Parcel parcel) {
298 final int mediaSizeCount = parcel.readInt();
299 if (mediaSizeCount > 0 && mMediaSizes == null) {
300 mMediaSizes = new ArrayList<MediaSize>();
301 }
302 for (int i = 0; i < mediaSizeCount; i++) {
303 mMediaSizes.add(MediaSize.createFromParcel(parcel));
304 }
305 }
306
307 private void writeResolutions(Parcel parcel) {
308 if (mResolutions == null) {
309 parcel.writeInt(0);
310 return;
311 }
312 final int resolutionCount = mResolutions.size();
313 parcel.writeInt(resolutionCount);
314 for (int i = 0; i < resolutionCount; i++) {
315 mResolutions.get(i).writeToParcel(parcel);
316 }
317 }
318
319 private void readResolutions(Parcel parcel) {
320 final int resolutionCount = parcel.readInt();
321 if (resolutionCount > 0 && mResolutions == null) {
322 mResolutions = new ArrayList<Resolution>();
323 }
324 for (int i = 0; i < resolutionCount; i++) {
325 mResolutions.add(Resolution.createFromParcel(parcel));
326 }
327 }
328
329 private void writeMargins(Margins margins, Parcel parcel) {
330 if (margins == null) {
331 parcel.writeInt(0);
332 } else {
333 parcel.writeInt(1);
334 margins.writeToParcel(parcel);
335 }
336 }
337
338 private Margins readMargins(Parcel parcel) {
339 return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
340 }
341
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700342 private void readDefaults(Parcel parcel) {
343 final int defaultCount = parcel.readInt();
344 for (int i = 0; i < defaultCount; i++) {
345 mDefaults[i] = parcel.readInt();
346 }
347 }
348
349 private void writeDefaults(Parcel parcel) {
350 final int defaultCount = mDefaults.length;
351 parcel.writeInt(defaultCount);
352 for (int i = 0; i < defaultCount; i++) {
353 parcel.writeInt(mDefaults[i]);
354 }
355 }
356
357 /**
358 * Builder for creating of a {@link PrinterInfo}. This class is responsible
359 * to enforce that all required attributes have at least one default value.
360 * In other words, this class creates only well-formed {@link PrinterInfo}s.
361 * <p>
362 * Look at the individual methods for a reference whether a property is
363 * required or if it is optional.
364 * </p>
365 */
366 public static final class Builder {
367 private final PrinterCapabilitiesInfo mPrototype;
368
369 /**
370 * Creates a new instance.
371 *
372 * @param printerId The printer id. Cannot be null.
373 *
374 * @throws IllegalArgumentException If the printer id is null.
375 */
376 public Builder(PrinterId printerId) {
377 if (printerId == null) {
378 throw new IllegalArgumentException("printerId cannot be null.");
379 }
380 mPrototype = new PrinterCapabilitiesInfo();
381 }
382
383 /**
384 * Adds a supported media size.
385 * <p>
386 * <strong>Required:</strong> Yes
387 * </p>
388 *
389 * @param mediaSize A media size.
390 * @param isDefault Whether this is the default.
391 * @return This builder.
392 * @throws IllegalArgumentException If set as default and there
393 * is already a default.
394 *
395 * @see PrintAttributes.MediaSize
396 */
397 public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
398 if (mPrototype.mMediaSizes == null) {
399 mPrototype.mMediaSizes = new ArrayList<MediaSize>();
400 }
401 final int insertionIndex = mPrototype.mMediaSizes.size();
402 mPrototype.mMediaSizes.add(mediaSize);
403 if (isDefault) {
404 throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
405 mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex;
406 }
407 return this;
408 }
409
410 /**
411 * Adds a supported resolution.
412 * <p>
413 * <strong>Required:</strong> Yes
414 * </p>
415 *
416 * @param resolution A resolution.
417 * @param isDefault Whether this is the default.
418 * @return This builder.
419 *
420 * @throws IllegalArgumentException If set as default and there
421 * is already a default.
422 *
423 * @see PrintAttributes.Resolution
424 */
425 public Builder addResolution(Resolution resolution, boolean isDefault) {
426 if (mPrototype.mResolutions == null) {
427 mPrototype.mResolutions = new ArrayList<Resolution>();
428 }
429 final int insertionIndex = mPrototype.mResolutions.size();
430 mPrototype.mResolutions.add(resolution);
431 if (isDefault) {
432 throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
433 mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex;
434 }
435 return this;
436 }
437
438 /**
Svetoslav651dd4e2013-09-12 14:37:47 -0700439 * Sets the minimal margins. These are the minimal margins
440 * the printer physically supports.
441 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700442 * <p>
Svetoslav651dd4e2013-09-12 14:37:47 -0700443 * <strong>Required:</strong> Yes
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700444 * </p>
445 *
446 * @param margins The margins.
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700447 * @return This builder.
448 *
Svetoslav651dd4e2013-09-12 14:37:47 -0700449 * @throws IllegalArgumentException If margins are <code>null</code>.
450 *
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700451 * @see PrintAttributes.Margins
452 */
Svetoslav651dd4e2013-09-12 14:37:47 -0700453 public Builder setMinMargins(Margins margins) {
454 if (margins == null) {
455 throw new IllegalArgumentException("margins cannot be null");
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700456 }
457 mPrototype.mMinMargins = margins;
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700458 return this;
459 }
460
461 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700462 * Sets the color modes.
463 * <p>
464 * <strong>Required:</strong> Yes
465 * </p>
466 *
467 * @param colorModes The color mode bit mask.
468 * @param defaultColorMode The default color mode.
469 * @return This builder.
470 *
471 * @throws IllegalArgumentException If color modes contains an invalid
472 * mode bit or if the default color mode is invalid.
473 *
474 * @see PrintAttributes#COLOR_MODE_COLOR
475 * @see PrintAttributes#COLOR_MODE_MONOCHROME
476 */
477 public Builder setColorModes(int colorModes, int defaultColorMode) {
478 int currentModes = colorModes;
479 while (currentModes > 0) {
480 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
481 currentModes &= ~currentMode;
482 PrintAttributes.enforceValidColorMode(currentMode);
483 }
484 if ((colorModes & defaultColorMode) == 0) {
485 throw new IllegalArgumentException("Default color mode not in color modes.");
486 }
487 PrintAttributes.enforceValidColorMode(colorModes);
488 mPrototype.mColorModes = colorModes;
489 mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
490 return this;
491 }
492
493 /**
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700494 * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
495 * required properties have need specified. See individual methods
496 * in this class for reference about required attributes.
497 *
498 * @return A new {@link PrinterCapabilitiesInfo}.
499 *
500 * @throws IllegalStateException If a required attribute was not specified.
501 */
Svetoslav651dd4e2013-09-12 14:37:47 -0700502 public PrinterCapabilitiesInfo build() {
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700503 if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
504 throw new IllegalStateException("No media size specified.");
505 }
506 if (mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] == DEFAULT_UNDEFINED) {
507 throw new IllegalStateException("No default media size specified.");
508 }
509 if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) {
510 throw new IllegalStateException("No resolution specified.");
511 }
512 if (mPrototype.mDefaults[PROPERTY_RESOLUTION] == DEFAULT_UNDEFINED) {
513 throw new IllegalStateException("No default resolution specified.");
514 }
515 if (mPrototype.mColorModes == 0) {
516 throw new IllegalStateException("No color mode specified.");
517 }
518 if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
519 throw new IllegalStateException("No default color mode specified.");
520 }
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700521 if (mPrototype.mMinMargins == null) {
Svetoslav651dd4e2013-09-12 14:37:47 -0700522 throw new IllegalArgumentException("margins cannot be null");
Svetoslav Ganov798bed62013-08-11 12:29:39 -0700523 }
524 return new PrinterCapabilitiesInfo(mPrototype);
525 }
526
527 private void throwIfDefaultAlreadySpecified(int propertyIndex) {
528 if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) {
529 throw new IllegalArgumentException("Default already specified.");
530 }
531 }
532 }
533
534 public static final Parcelable.Creator<PrinterCapabilitiesInfo> CREATOR =
535 new Parcelable.Creator<PrinterCapabilitiesInfo>() {
536 @Override
537 public PrinterCapabilitiesInfo createFromParcel(Parcel parcel) {
538 return new PrinterCapabilitiesInfo(parcel);
539 }
540
541 @Override
542 public PrinterCapabilitiesInfo[] newArray(int size) {
543 return new PrinterCapabilitiesInfo[size];
544 }
545 };
546}
547