PrinterInfo.java revision bb9f686b40743df2642b7d3b7778dbf7284ae665
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.annotation.DrawableRes; 20import android.annotation.NonNull; 21import android.annotation.Nullable; 22import android.annotation.TestApi; 23import android.app.PendingIntent; 24import android.content.Context; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.PackageInfo; 27import android.content.pm.PackageManager; 28import android.content.pm.PackageManager.NameNotFoundException; 29import android.graphics.drawable.Drawable; 30import android.graphics.drawable.Icon; 31import android.os.Parcel; 32import android.os.Parcelable; 33import android.text.TextUtils; 34 35/** 36 * This class represents the description of a printer. Instances of 37 * this class are created by print services to report to the system 38 * the printers they manage. The information of this class has two 39 * major components, printer properties such as name, id, status, 40 * description and printer capabilities which describe the various 41 * print modes a printer supports such as media sizes, margins, etc. 42 */ 43public final class PrinterInfo implements Parcelable { 44 45 /** Printer status: the printer is idle and ready to print. */ 46 public static final int STATUS_IDLE = 1; 47 48 /** Printer status: the printer is busy printing. */ 49 public static final int STATUS_BUSY = 2; 50 51 /** Printer status: the printer is not available. */ 52 public static final int STATUS_UNAVAILABLE = 3; 53 54 private PrinterId mId; 55 56 /** Resource inside the printer's services's package to be used as an icon */ 57 private int mIconResourceId; 58 59 /** If a custom icon can be loaded for the printer */ 60 private boolean mHasCustomPrinterIcon; 61 62 /** The generation of the icon in the cache. */ 63 private int mCustomPrinterIconGen; 64 65 /** Intent that launches the activity showing more information about the printer. */ 66 private PendingIntent mInfoIntent; 67 68 private String mName; 69 70 private int mStatus; 71 72 private String mDescription; 73 74 private PrinterCapabilitiesInfo mCapabilities; 75 76 private PrinterInfo() { 77 /* do nothing */ 78 } 79 80 private PrinterInfo(PrinterInfo prototype) { 81 copyFrom(prototype); 82 } 83 84 /** 85 * @hide 86 */ 87 public void copyFrom(PrinterInfo other) { 88 if (this == other) { 89 return; 90 } 91 mId = other.mId; 92 mName = other.mName; 93 mStatus = other.mStatus; 94 mDescription = other.mDescription; 95 if (other.mCapabilities != null) { 96 if (mCapabilities != null) { 97 mCapabilities.copyFrom(other.mCapabilities); 98 } else { 99 mCapabilities = new PrinterCapabilitiesInfo(other.mCapabilities); 100 } 101 } else { 102 mCapabilities = null; 103 } 104 mIconResourceId = other.mIconResourceId; 105 mHasCustomPrinterIcon = other.mHasCustomPrinterIcon; 106 mCustomPrinterIconGen = other.mCustomPrinterIconGen; 107 mInfoIntent = other.mInfoIntent; 108 } 109 110 /** 111 * Get the globally unique printer id. 112 * 113 * @return The printer id. 114 */ 115 public PrinterId getId() { 116 return mId; 117 } 118 119 /** 120 * Get the icon to be used for this printer. If no per printer icon is available, the printer's 121 * service's icon is returned. If the printer has a custom icon this icon might get requested 122 * asynchronously. Once the icon is loaded the discovery sessions will be notified that the 123 * printer changed. 124 * 125 * @param context The context that will be using the icons 126 * @return The icon to be used for the printer or null if no icon could be found. 127 * @hide 128 */ 129 @TestApi 130 public @Nullable Drawable loadIcon(@NonNull Context context) { 131 Drawable drawable = null; 132 PackageManager packageManager = context.getPackageManager(); 133 134 if (mHasCustomPrinterIcon) { 135 PrintManager printManager = (PrintManager) context 136 .getSystemService(Context.PRINT_SERVICE); 137 138 Icon icon = printManager.getCustomPrinterIcon(mId); 139 140 if (icon != null) { 141 drawable = icon.loadDrawable(context); 142 } 143 } 144 145 if (drawable == null) { 146 try { 147 String packageName = mId.getServiceName().getPackageName(); 148 PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0); 149 ApplicationInfo appInfo = packageInfo.applicationInfo; 150 151 // If no custom icon is available, try the icon from the resources 152 if (mIconResourceId != 0) { 153 drawable = packageManager.getDrawable(packageName, mIconResourceId, appInfo); 154 } 155 156 // Fall back to the printer's service's icon if no per printer icon could be found 157 if (drawable == null) { 158 drawable = appInfo.loadIcon(packageManager); 159 } 160 } catch (NameNotFoundException e) { 161 } 162 } 163 164 return drawable; 165 } 166 167 /** 168 * Get the printer name. 169 * 170 * @return The printer name. 171 */ 172 public String getName() { 173 return mName; 174 } 175 176 /** 177 * Gets the printer status. 178 * 179 * @return The status. 180 * 181 * @see #STATUS_BUSY 182 * @see #STATUS_IDLE 183 * @see #STATUS_UNAVAILABLE 184 */ 185 public int getStatus() { 186 return mStatus; 187 } 188 189 /** 190 * Gets the printer description. 191 * 192 * @return The description. 193 */ 194 public String getDescription() { 195 return mDescription; 196 } 197 198 /** 199 * Get the {@link PendingIntent} that launches the activity showing more information about the 200 * printer. 201 * 202 * @return the {@link PendingIntent} that launches the activity showing more information about 203 * the printer or null if it is not configured 204 * @hide 205 */ 206 public @Nullable PendingIntent getInfoIntent() { 207 return mInfoIntent; 208 } 209 210 /** 211 * Gets the printer capabilities. 212 * 213 * @return The capabilities. 214 */ 215 public PrinterCapabilitiesInfo getCapabilities() { 216 return mCapabilities; 217 } 218 219 private PrinterInfo(Parcel parcel) { 220 mId = parcel.readParcelable(null); 221 mName = parcel.readString(); 222 mStatus = parcel.readInt(); 223 mDescription = parcel.readString(); 224 mCapabilities = parcel.readParcelable(null); 225 mIconResourceId = parcel.readInt(); 226 mHasCustomPrinterIcon = parcel.readByte() != 0; 227 mCustomPrinterIconGen = parcel.readInt(); 228 mInfoIntent = parcel.readParcelable(null); 229 } 230 231 @Override 232 public int describeContents() { 233 return 0; 234 } 235 236 @Override 237 public void writeToParcel(Parcel parcel, int flags) { 238 parcel.writeParcelable(mId, flags); 239 parcel.writeString(mName); 240 parcel.writeInt(mStatus); 241 parcel.writeString(mDescription); 242 parcel.writeParcelable(mCapabilities, flags); 243 parcel.writeInt(mIconResourceId); 244 parcel.writeByte((byte) (mHasCustomPrinterIcon ? 1 : 0)); 245 parcel.writeInt(mCustomPrinterIconGen); 246 parcel.writeParcelable(mInfoIntent, flags); 247 } 248 249 @Override 250 public int hashCode() { 251 final int prime = 31; 252 int result = 1; 253 result = prime * result + ((mId != null) ? mId.hashCode() : 0); 254 result = prime * result + ((mName != null) ? mName.hashCode() : 0); 255 result = prime * result + mStatus; 256 result = prime * result + ((mDescription != null) ? mDescription.hashCode() : 0); 257 result = prime * result + ((mCapabilities != null) ? mCapabilities.hashCode() : 0); 258 result = prime * result + mIconResourceId; 259 result = prime * result + (mHasCustomPrinterIcon ? 1 : 0); 260 result = prime * result + mCustomPrinterIconGen; 261 result = prime * result + ((mInfoIntent != null) ? mInfoIntent.hashCode() : 0); 262 return result; 263 } 264 265 /** 266 * Compare two {@link PrinterInfo printerInfos} in all aspects beside being null and the 267 * {@link #mStatus}. 268 * 269 * @param other the other {@link PrinterInfo} 270 * @return true iff the infos are equivalent 271 * @hide 272 */ 273 public boolean equalsIgnoringStatus(PrinterInfo other) { 274 if (mId == null) { 275 if (other.mId != null) { 276 return false; 277 } 278 } else if (!mId.equals(other.mId)) { 279 return false; 280 } 281 if (!TextUtils.equals(mName, other.mName)) { 282 return false; 283 } 284 if (!TextUtils.equals(mDescription, other.mDescription)) { 285 return false; 286 } 287 if (mCapabilities == null) { 288 if (other.mCapabilities != null) { 289 return false; 290 } 291 } else if (!mCapabilities.equals(other.mCapabilities)) { 292 return false; 293 } 294 if (mIconResourceId != other.mIconResourceId) { 295 return false; 296 } 297 if (mHasCustomPrinterIcon != other.mHasCustomPrinterIcon) { 298 return false; 299 } 300 if (mCustomPrinterIconGen != other.mCustomPrinterIconGen) { 301 return false; 302 } 303 if (mInfoIntent == null) { 304 if (other.mInfoIntent != null) { 305 return false; 306 } 307 } else if (!mInfoIntent.equals(other.mInfoIntent)) { 308 return false; 309 } 310 return true; 311 } 312 313 @Override 314 public boolean equals(Object obj) { 315 if (this == obj) { 316 return true; 317 } 318 if (obj == null) { 319 return false; 320 } 321 if (getClass() != obj.getClass()) { 322 return false; 323 } 324 PrinterInfo other = (PrinterInfo) obj; 325 if (!equalsIgnoringStatus(other)) { 326 return false; 327 } 328 if (mStatus != other.mStatus) { 329 return false; 330 } 331 return true; 332 } 333 334 @Override 335 public String toString() { 336 StringBuilder builder = new StringBuilder(); 337 builder.append("PrinterInfo{"); 338 builder.append("id=").append(mId); 339 builder.append(", name=").append(mName); 340 builder.append(", status=").append(mStatus); 341 builder.append(", description=").append(mDescription); 342 builder.append(", capabilities=").append(mCapabilities); 343 builder.append(", iconResId=").append(mIconResourceId); 344 builder.append(", hasCustomPrinterIcon=").append(mHasCustomPrinterIcon); 345 builder.append(", customPrinterIconGen=").append(mCustomPrinterIconGen); 346 builder.append(", infoIntent=").append(mInfoIntent); 347 builder.append("\"}"); 348 return builder.toString(); 349 } 350 351 /** 352 * Builder for creating of a {@link PrinterInfo}. 353 */ 354 public static final class Builder { 355 private final PrinterInfo mPrototype; 356 357 /** 358 * Constructor. 359 * 360 * @param printerId The printer id. Cannot be null. 361 * @param name The printer name. Cannot be empty. 362 * @param status The printer status. Must be a valid status. 363 * @throws IllegalArgumentException If the printer id is null, or the 364 * printer name is empty or the status is not a valid one. 365 */ 366 public Builder(PrinterId printerId, String name, int status) { 367 if (printerId == null) { 368 throw new IllegalArgumentException("printerId cannot be null."); 369 } 370 if (TextUtils.isEmpty(name)) { 371 throw new IllegalArgumentException("name cannot be empty."); 372 } 373 if (!isValidStatus(status)) { 374 throw new IllegalArgumentException("status is invalid."); 375 } 376 mPrototype = new PrinterInfo(); 377 mPrototype.mId = printerId; 378 mPrototype.mName = name; 379 mPrototype.mStatus = status; 380 } 381 382 /** 383 * Constructor. 384 * 385 * @param other Other info from which to start building. 386 */ 387 public Builder(PrinterInfo other) { 388 mPrototype = new PrinterInfo(); 389 mPrototype.copyFrom(other); 390 } 391 392 /** 393 * Sets the printer status. 394 * 395 * @param status The status. 396 * @return This builder. 397 * 398 * @see PrinterInfo#STATUS_IDLE 399 * @see PrinterInfo#STATUS_BUSY 400 * @see PrinterInfo#STATUS_UNAVAILABLE 401 */ 402 public Builder setStatus(int status) { 403 mPrototype.mStatus = status; 404 return this; 405 } 406 407 /** 408 * Set a drawable resource as icon for this printer. If no icon is set the printer's 409 * service's icon is used for the printer. 410 * 411 * @return This builder. 412 * @see PrinterInfo.Builder#setHasCustomPrinterIcon 413 */ 414 public @NonNull Builder setIconResourceId(@DrawableRes int iconResourceId) { 415 mPrototype.mIconResourceId = iconResourceId; 416 return this; 417 } 418 419 /** 420 * Declares that the print service can load a custom per printer's icon. If both 421 * {@link PrinterInfo.Builder#setIconResourceId} and a custom icon are set the resource icon 422 * is shown while the custom icon loads but then the custom icon is used. If 423 * {@link PrinterInfo.Builder#setIconResourceId} is not set the printer's service's icon is 424 * shown while loading. 425 * <p> 426 * The icon is requested asynchronously and only when needed via 427 * {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon}. 428 * </p> 429 * 430 * @return This builder. 431 */ 432 public @NonNull Builder setHasCustomPrinterIcon() { 433 mPrototype.mHasCustomPrinterIcon = true; 434 return this; 435 } 436 437 /** 438 * Sets the <strong>localized</strong> printer name which 439 * is shown to the user 440 * 441 * @param name The name. 442 * @return This builder. 443 */ 444 public Builder setName(String name) { 445 mPrototype.mName = name; 446 return this; 447 } 448 449 /** 450 * Sets the <strong>localized</strong> printer description 451 * which is shown to the user 452 * 453 * @param description The description. 454 * @return This builder. 455 */ 456 public Builder setDescription(String description) { 457 mPrototype.mDescription = description; 458 return this; 459 } 460 461 /** 462 * Sets the {@link PendingIntent} that launches an activity showing more information about 463 * the printer. 464 * 465 * @param infoIntent The {@link PendingIntent intent}. 466 * @return This builder. 467 */ 468 public @NonNull Builder setInfoIntent(@NonNull PendingIntent infoIntent) { 469 mPrototype.mInfoIntent = infoIntent; 470 return this; 471 } 472 473 /** 474 * Sets the printer capabilities. 475 * 476 * @param capabilities The capabilities. 477 * @return This builder. 478 */ 479 public Builder setCapabilities(PrinterCapabilitiesInfo capabilities) { 480 mPrototype.mCapabilities = capabilities; 481 return this; 482 } 483 484 /** 485 * Creates a new {@link PrinterInfo}. 486 * 487 * @return A new {@link PrinterInfo}. 488 */ 489 public PrinterInfo build() { 490 return mPrototype; 491 } 492 493 private boolean isValidStatus(int status) { 494 return (status == STATUS_IDLE 495 || status == STATUS_BUSY 496 || status == STATUS_UNAVAILABLE); 497 } 498 499 /** 500 * Increments the generation number of the custom printer icon. As the {@link PrinterInfo} 501 * does not match the previous one anymore, users of the {@link PrinterInfo} will reload the 502 * icon if needed. 503 * 504 * @return This builder. 505 * @hide 506 */ 507 public @NonNull Builder incCustomPrinterIconGen() { 508 mPrototype.mCustomPrinterIconGen++; 509 return this; 510 } 511 } 512 513 public static final Parcelable.Creator<PrinterInfo> CREATOR = 514 new Parcelable.Creator<PrinterInfo>() { 515 @Override 516 public PrinterInfo createFromParcel(Parcel parcel) { 517 return new PrinterInfo(parcel); 518 } 519 520 @Override 521 public PrinterInfo[] newArray(int size) { 522 return new PrinterInfo[size]; 523 } 524 }; 525} 526