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