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