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