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