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.printservice;
18
19import android.annotation.NonNull;
20import android.annotation.SystemApi;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.pm.PackageManager;
24import android.content.pm.PackageManager.NameNotFoundException;
25import android.content.pm.ResolveInfo;
26import android.content.res.Resources;
27import android.content.res.TypedArray;
28import android.content.res.XmlResourceParser;
29import android.os.Parcel;
30import android.os.Parcelable;
31import android.util.AttributeSet;
32import android.util.Log;
33import android.util.Xml;
34
35import org.xmlpull.v1.XmlPullParser;
36import org.xmlpull.v1.XmlPullParserException;
37
38import java.io.IOException;
39
40/**
41 * This class describes a {@link PrintService}. A print service knows
42 * how to communicate with one or more printers over one or more protocols
43 * and exposes printers for use by the applications via the platform print
44 * APIs.
45 *
46 * @see PrintService
47 * @see android.print.PrintManager
48 *
49 * @hide
50 */
51@SystemApi
52public final class PrintServiceInfo implements Parcelable {
53
54    private static final String LOG_TAG = PrintServiceInfo.class.getSimpleName();
55
56    private static final String TAG_PRINT_SERVICE = "print-service";
57
58    private final String mId;
59
60    private boolean mIsEnabled;
61
62    private final ResolveInfo mResolveInfo;
63
64    private final String mSettingsActivityName;
65
66    private final String mAddPrintersActivityName;
67
68    private final String mAdvancedPrintOptionsActivityName;
69
70    /**
71     * Creates a new instance.
72     *
73     * @hide
74     */
75    public PrintServiceInfo(Parcel parcel) {
76        mId = parcel.readString();
77        mIsEnabled = parcel.readByte() != 0;
78        mResolveInfo = parcel.readParcelable(null);
79        mSettingsActivityName = parcel.readString();
80        mAddPrintersActivityName = parcel.readString();
81        mAdvancedPrintOptionsActivityName = parcel.readString();
82    }
83
84    /**
85     * Creates a new instance.
86     *
87     * @param resolveInfo The service resolve info.
88     * @param settingsActivityName Optional settings activity name.
89     * @param addPrintersActivityName Optional add printers activity name.
90     * @param advancedPrintOptionsActivityName Optional advanced print options activity.
91     *
92     * @hide
93     */
94    public PrintServiceInfo(ResolveInfo resolveInfo, String settingsActivityName,
95            String addPrintersActivityName, String advancedPrintOptionsActivityName) {
96        mId = new ComponentName(resolveInfo.serviceInfo.packageName,
97                resolveInfo.serviceInfo.name).flattenToString();
98        mResolveInfo = resolveInfo;
99        mSettingsActivityName = settingsActivityName;
100        mAddPrintersActivityName = addPrintersActivityName;
101        mAdvancedPrintOptionsActivityName = advancedPrintOptionsActivityName;
102    }
103
104    /**
105     * Return the component name for this print service.
106     *
107     * @return The component name for this print service.
108     */
109    public @NonNull ComponentName getComponentName() {
110        return new ComponentName(mResolveInfo.serviceInfo.packageName,
111                mResolveInfo.serviceInfo.name);
112    }
113
114    /**
115     * Creates a new instance.
116     *
117     * @param context Context for accessing resources.
118     * @param resolveInfo The service resolve info.
119     * @return The created instance.
120     *
121     * @hide
122     */
123    public static PrintServiceInfo create(Context context, ResolveInfo resolveInfo) {
124        String settingsActivityName = null;
125        String addPrintersActivityName = null;
126        String advancedPrintOptionsActivityName = null;
127
128        XmlResourceParser parser = null;
129        PackageManager packageManager = context.getPackageManager();
130        parser = resolveInfo.serviceInfo.loadXmlMetaData(packageManager,
131                PrintService.SERVICE_META_DATA);
132        if (parser != null) {
133            try {
134                int type = 0;
135                while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
136                    type = parser.next();
137                }
138
139                String nodeName = parser.getName();
140                if (!TAG_PRINT_SERVICE.equals(nodeName)) {
141                    Log.e(LOG_TAG, "Ignoring meta-data that does not start with "
142                            + TAG_PRINT_SERVICE + " tag");
143                } else {
144                    Resources resources = packageManager.getResourcesForApplication(
145                            resolveInfo.serviceInfo.applicationInfo);
146                    AttributeSet allAttributes = Xml.asAttributeSet(parser);
147                    TypedArray attributes = resources.obtainAttributes(allAttributes,
148                            com.android.internal.R.styleable.PrintService);
149
150                    settingsActivityName = attributes.getString(
151                            com.android.internal.R.styleable.PrintService_settingsActivity);
152
153                    addPrintersActivityName = attributes.getString(
154                            com.android.internal.R.styleable.PrintService_addPrintersActivity);
155
156                    advancedPrintOptionsActivityName = attributes.getString(com.android.internal
157                            .R.styleable.PrintService_advancedPrintOptionsActivity);
158
159                    attributes.recycle();
160                }
161            } catch (IOException ioe) {
162                Log.w(LOG_TAG, "Error reading meta-data:" + ioe);
163            } catch (XmlPullParserException xppe) {
164                Log.w(LOG_TAG, "Error reading meta-data:" + xppe);
165            } catch (NameNotFoundException e) {
166                Log.e(LOG_TAG, "Unable to load resources for: "
167                        + resolveInfo.serviceInfo.packageName);
168            } finally {
169                if (parser != null) {
170                    parser.close();
171                }
172            }
173        }
174
175        return new PrintServiceInfo(resolveInfo, settingsActivityName,
176                addPrintersActivityName, advancedPrintOptionsActivityName);
177    }
178
179    /**
180     * The accessibility service id.
181     * <p>
182     * <strong>Generated by the system.</strong>
183     * </p>
184     *
185     * @return The id.
186     *
187     * @hide
188     */
189    public String getId() {
190        return mId;
191    }
192
193    /**
194     * If the service was enabled when it was read from the system.
195     *
196     * @return The id.
197     *
198     * @hide
199     */
200    public boolean isEnabled() {
201        return mIsEnabled;
202    }
203
204    /**
205     * Mark a service as enabled or not
206     *
207     * @param isEnabled If the service should be marked as enabled.
208     *
209     * @hide
210     */
211    public void setIsEnabled(boolean isEnabled) {
212        mIsEnabled = isEnabled;
213    }
214
215    /**
216     * The service {@link ResolveInfo}.
217     *
218     * @return The info.
219     *
220     * @hide
221     */
222    public ResolveInfo getResolveInfo() {
223        return mResolveInfo;
224    }
225
226    /**
227     * The settings activity name.
228     * <p>
229     * <strong>Statically set from
230     * {@link PrintService#SERVICE_META_DATA meta-data}.</strong>
231     * </p>
232     *
233     * @return The settings activity name.
234     *
235     * @hide
236     */
237    public String getSettingsActivityName() {
238        return mSettingsActivityName;
239    }
240
241    /**
242     * The add printers activity name.
243     * <p>
244     * <strong>Statically set from
245     * {@link PrintService#SERVICE_META_DATA meta-data}.</strong>
246     * </p>
247     *
248     * @return The add printers activity name.
249     *
250     * @hide
251     */
252    public String getAddPrintersActivityName() {
253        return mAddPrintersActivityName;
254    }
255
256    /**
257     * The advanced print options activity name.
258     * <p>
259     * <strong>Statically set from
260     * {@link PrintService#SERVICE_META_DATA meta-data}.</strong>
261     * </p>
262     *
263     * @return The advanced print options activity name.
264     *
265     * @hide
266     */
267    public String getAdvancedOptionsActivityName() {
268        return mAdvancedPrintOptionsActivityName;
269    }
270
271    /**
272     * {@inheritDoc}
273     */
274    @Override
275    public int describeContents() {
276        return 0;
277    }
278
279    @Override
280    public void writeToParcel(Parcel parcel, int flagz) {
281        parcel.writeString(mId);
282        parcel.writeByte((byte)(mIsEnabled ? 1 : 0));
283        parcel.writeParcelable(mResolveInfo, 0);
284        parcel.writeString(mSettingsActivityName);
285        parcel.writeString(mAddPrintersActivityName);
286        parcel.writeString(mAdvancedPrintOptionsActivityName);
287    }
288
289    @Override
290    public int hashCode() {
291        return 31 + ((mId == null) ? 0 : mId.hashCode());
292    }
293
294    @Override
295    public boolean equals(Object obj) {
296        if (this == obj) {
297            return true;
298        }
299        if (obj == null) {
300            return false;
301        }
302        if (getClass() != obj.getClass()) {
303            return false;
304        }
305        PrintServiceInfo other = (PrintServiceInfo) obj;
306        if (mId == null) {
307            if (other.mId != null) {
308                return false;
309            }
310        } else if (!mId.equals(other.mId)) {
311            return false;
312        }
313        return true;
314    }
315
316    @Override
317    public String toString() {
318        StringBuilder builder = new StringBuilder();
319        builder.append("PrintServiceInfo{");
320        builder.append("id=").append(mId);
321        builder.append("isEnabled=").append(mIsEnabled);
322        builder.append(", resolveInfo=").append(mResolveInfo);
323        builder.append(", settingsActivityName=").append(mSettingsActivityName);
324        builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
325        builder.append(", advancedPrintOptionsActivityName=")
326                .append(mAdvancedPrintOptionsActivityName);
327        builder.append("}");
328        return builder.toString();
329    }
330
331    public static final Parcelable.Creator<PrintServiceInfo> CREATOR =
332            new Parcelable.Creator<PrintServiceInfo>() {
333        @Override
334        public PrintServiceInfo createFromParcel(Parcel parcel) {
335            return new PrintServiceInfo(parcel);
336        }
337
338        @Override
339        public PrintServiceInfo[] newArray(int size) {
340            return new PrintServiceInfo[size];
341        }
342    };
343}
344