PrinterCapabilitiesInfo.java revision 651dd4e6ee6510caf9f15c51094a11121af17ec2
1/* 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; 24 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; 42 private static final int PROPERTY_COLOR_MODE = 2; 43 private static final int PROPERTY_COUNT = 3; 44 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; 50 51 private int mColorModes; 52 53 private final int[] mDefaults = new int[PROPERTY_COUNT]; 54 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) { 73 if (this == other) { 74 return; 75 } 76 77 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 101 mColorModes = other.mColorModes; 102 103 final int defaultCount = other.mDefaults.length; 104 for (int i = 0; i < defaultCount; i++) { 105 mDefaults[i] = other.mDefaults[i]; 106 } 107 } 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 /** 128 * Gets the minimal margins. These are the minimal margins 129 * the printer physically supports. 130 * 131 * @return The minimal margins. 132 */ 133 public Margins getMinMargins() { 134 return mMinMargins; 135 } 136 137 /** 138 * 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 /** 150 * Gets the default print attributes. 151 * 152 * @return The default attributes. 153 */ 154 public PrintAttributes getDefaults() { 155 PrintAttributes.Builder builder = new PrintAttributes.Builder(); 156 157 builder.setMinMargins(mMinMargins); 158 159 final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE]; 160 if (mediaSizeIndex >= 0) { 161 builder.setMediaSize(mMediaSizes.get(mediaSizeIndex)); 162 } 163 164 final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION]; 165 if (resolutionIndex >= 0) { 166 builder.setResolution(mResolutions.get(resolutionIndex)); 167 } 168 169 final int colorMode = mDefaults[PROPERTY_COLOR_MODE]; 170 if (colorMode > 0) { 171 builder.setColorMode(colorMode); 172 } 173 174 return builder.build(); 175 } 176 177 private PrinterCapabilitiesInfo(Parcel parcel) { 178 mMinMargins = readMargins(parcel); 179 readMediaSizes(parcel); 180 readResolutions(parcel); 181 182 mColorModes = parcel.readInt(); 183 184 readDefaults(parcel); 185 } 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); 197 198 parcel.writeInt(mColorModes); 199 200 writeDefaults(parcel); 201 } 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()); 210 result = prime * result + mColorModes; 211 result = prime * result + Arrays.hashCode(mDefaults); 212 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 } 248 if (mColorModes != other.mColorModes) { 249 return false; 250 } 251 if (!Arrays.equals(mDefaults, other.mDefaults)) { 252 return false; 253 } 254 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); 264 builder.append(", colorModes=").append(colorModesToString()); 265 builder.append("\"}"); 266 return builder.toString(); 267 } 268 269 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; 276 if (builder.length() > 1) { 277 builder.append(", "); 278 } 279 builder.append(PrintAttributes.colorModeToString(colorMode)); 280 } 281 builder.append(']'); 282 return builder.toString(); 283 } 284 285 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 342 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 /** 439 * Sets the minimal margins. These are the minimal margins 440 * the printer physically supports. 441 * 442 * <p> 443 * <strong>Required:</strong> Yes 444 * </p> 445 * 446 * @param margins The margins. 447 * @return This builder. 448 * 449 * @throws IllegalArgumentException If margins are <code>null</code>. 450 * 451 * @see PrintAttributes.Margins 452 */ 453 public Builder setMinMargins(Margins margins) { 454 if (margins == null) { 455 throw new IllegalArgumentException("margins cannot be null"); 456 } 457 mPrototype.mMinMargins = margins; 458 return this; 459 } 460 461 /** 462 * 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 /** 494 * 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 */ 502 public PrinterCapabilitiesInfo build() { 503 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 } 521 if (mPrototype.mMinMargins == null) { 522 throw new IllegalArgumentException("margins cannot be null"); 523 } 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 548