1/*
2 * Copyright (C) 2009 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.app;
18
19import org.xmlpull.v1.XmlPullParser;
20import org.xmlpull.v1.XmlPullParserException;
21
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.pm.ApplicationInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.ResolveInfo;
27import android.content.pm.ServiceInfo;
28import android.content.pm.PackageManager.NameNotFoundException;
29import android.content.res.Resources.NotFoundException;
30import android.content.res.Resources;
31import android.content.res.TypedArray;
32import android.content.res.XmlResourceParser;
33import android.graphics.drawable.Drawable;
34import android.net.Uri;
35import android.os.Parcel;
36import android.os.Parcelable;
37import android.service.wallpaper.WallpaperService;
38import android.util.AttributeSet;
39import android.util.Printer;
40import android.util.Xml;
41
42import java.io.IOException;
43
44/**
45 * This class is used to specify meta information of a wallpaper service.
46 */
47public final class WallpaperInfo implements Parcelable {
48    static final String TAG = "WallpaperInfo";
49
50    /**
51     * The Service that implements this wallpaper component.
52     */
53    final ResolveInfo mService;
54
55    /**
56     * The wallpaper setting activity's name, to
57     * launch the setting activity of this wallpaper.
58     */
59    final String mSettingsActivityName;
60
61    /**
62     * Resource identifier for this wallpaper's thumbnail image.
63     */
64    final int mThumbnailResource;
65
66    /**
67     * Resource identifier for a string indicating the author of the wallpaper.
68     */
69    final int mAuthorResource;
70
71    /**
72     * Resource identifier for a string containing a short description of the wallpaper.
73     */
74    final int mDescriptionResource;
75
76    final int mContextUriResource;
77    final int mContextDescriptionResource;
78    final boolean mShowMetadataInPreview;
79
80    /**
81     * Constructor.
82     *
83     * @param context The Context in which we are parsing the wallpaper.
84     * @param service The ResolveInfo returned from the package manager about
85     * this wallpaper's component.
86     */
87    public WallpaperInfo(Context context, ResolveInfo service)
88            throws XmlPullParserException, IOException {
89        mService = service;
90        ServiceInfo si = service.serviceInfo;
91
92        PackageManager pm = context.getPackageManager();
93        String settingsActivityComponent = null;
94        int thumbnailRes = -1;
95        int authorRes = -1;
96        int descriptionRes = -1;
97        int contextUriRes = -1;
98        int contextDescriptionRes = -1;
99        boolean showMetadataInPreview = false;
100
101        XmlResourceParser parser = null;
102        try {
103            parser = si.loadXmlMetaData(pm, WallpaperService.SERVICE_META_DATA);
104            if (parser == null) {
105                throw new XmlPullParserException("No "
106                        + WallpaperService.SERVICE_META_DATA + " meta-data");
107            }
108
109            Resources res = pm.getResourcesForApplication(si.applicationInfo);
110
111            AttributeSet attrs = Xml.asAttributeSet(parser);
112
113            int type;
114            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
115                    && type != XmlPullParser.START_TAG) {
116            }
117
118            String nodeName = parser.getName();
119            if (!"wallpaper".equals(nodeName)) {
120                throw new XmlPullParserException(
121                        "Meta-data does not start with wallpaper tag");
122            }
123
124            TypedArray sa = res.obtainAttributes(attrs,
125                    com.android.internal.R.styleable.Wallpaper);
126            settingsActivityComponent = sa.getString(
127                    com.android.internal.R.styleable.Wallpaper_settingsActivity);
128
129            thumbnailRes = sa.getResourceId(
130                    com.android.internal.R.styleable.Wallpaper_thumbnail,
131                    -1);
132            authorRes = sa.getResourceId(
133                    com.android.internal.R.styleable.Wallpaper_author,
134                    -1);
135            descriptionRes = sa.getResourceId(
136                    com.android.internal.R.styleable.Wallpaper_description,
137                    -1);
138            contextUriRes = sa.getResourceId(
139                    com.android.internal.R.styleable.Wallpaper_contextUri,
140                    -1);
141            contextDescriptionRes = sa.getResourceId(
142                    com.android.internal.R.styleable.Wallpaper_contextDescription,
143                    -1);
144            showMetadataInPreview = sa.getBoolean(
145                    com.android.internal.R.styleable.Wallpaper_showMetadataInPreview,
146                    false);
147
148            sa.recycle();
149        } catch (NameNotFoundException e) {
150            throw new XmlPullParserException(
151                    "Unable to create context for: " + si.packageName);
152        } finally {
153            if (parser != null) parser.close();
154        }
155
156        mSettingsActivityName = settingsActivityComponent;
157        mThumbnailResource = thumbnailRes;
158        mAuthorResource = authorRes;
159        mDescriptionResource = descriptionRes;
160        mContextUriResource = contextUriRes;
161        mContextDescriptionResource = contextDescriptionRes;
162        mShowMetadataInPreview = showMetadataInPreview;
163    }
164
165    WallpaperInfo(Parcel source) {
166        mSettingsActivityName = source.readString();
167        mThumbnailResource = source.readInt();
168        mAuthorResource = source.readInt();
169        mDescriptionResource = source.readInt();
170        mContextUriResource = source.readInt();
171        mContextDescriptionResource = source.readInt();
172        mShowMetadataInPreview = source.readInt() != 0;
173        mService = ResolveInfo.CREATOR.createFromParcel(source);
174    }
175
176    /**
177     * Return the .apk package that implements this wallpaper.
178     */
179    public String getPackageName() {
180        return mService.serviceInfo.packageName;
181    }
182
183    /**
184     * Return the class name of the service component that implements
185     * this wallpaper.
186     */
187    public String getServiceName() {
188        return mService.serviceInfo.name;
189    }
190
191    /**
192     * Return the raw information about the Service implementing this
193     * wallpaper.  Do not modify the returned object.
194     */
195    public ServiceInfo getServiceInfo() {
196        return mService.serviceInfo;
197    }
198
199    /**
200     * Return the component of the service that implements this wallpaper.
201     */
202    public ComponentName getComponent() {
203        return new ComponentName(mService.serviceInfo.packageName,
204                mService.serviceInfo.name);
205    }
206
207    /**
208     * Load the user-displayed label for this wallpaper.
209     *
210     * @param pm Supply a PackageManager used to load the wallpaper's
211     * resources.
212     */
213    public CharSequence loadLabel(PackageManager pm) {
214        return mService.loadLabel(pm);
215    }
216
217    /**
218     * Load the user-displayed icon for this wallpaper.
219     *
220     * @param pm Supply a PackageManager used to load the wallpaper's
221     * resources.
222     */
223    public Drawable loadIcon(PackageManager pm) {
224        return mService.loadIcon(pm);
225    }
226
227    /**
228     * Load the thumbnail image for this wallpaper.
229     *
230     * @param pm Supply a PackageManager used to load the wallpaper's
231     * resources.
232     */
233    public Drawable loadThumbnail(PackageManager pm) {
234        if (mThumbnailResource < 0) return null;
235
236        return pm.getDrawable(mService.serviceInfo.packageName,
237                              mThumbnailResource,
238                              mService.serviceInfo.applicationInfo);
239    }
240
241    /**
242     * Return a string indicating the author(s) of this wallpaper.
243     */
244    public CharSequence loadAuthor(PackageManager pm) throws NotFoundException {
245        if (mAuthorResource <= 0) throw new NotFoundException();
246        String packageName = mService.resolvePackageName;
247        ApplicationInfo applicationInfo = null;
248        if (packageName == null) {
249            packageName = mService.serviceInfo.packageName;
250            applicationInfo = mService.serviceInfo.applicationInfo;
251        }
252        return pm.getText(packageName, mAuthorResource, applicationInfo);
253    }
254
255    /**
256     * Return a brief summary of this wallpaper's behavior.
257     */
258    public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
259        String packageName = mService.resolvePackageName;
260        ApplicationInfo applicationInfo = null;
261        if (packageName == null) {
262            packageName = mService.serviceInfo.packageName;
263            applicationInfo = mService.serviceInfo.applicationInfo;
264        }
265        if (mService.serviceInfo.descriptionRes != 0) {
266            return pm.getText(packageName, mService.serviceInfo.descriptionRes,
267                    applicationInfo);
268
269        }
270        if (mDescriptionResource <= 0) throw new NotFoundException();
271        return pm.getText(packageName, mDescriptionResource,
272                mService.serviceInfo.applicationInfo);
273    }
274
275    /**
276     * Returns an URI that specifies a link for further context about this wallpaper.
277     *
278     * @param pm An instance of {@link PackageManager} to retrieve the URI.
279     * @return The URI.
280     */
281    public Uri loadContextUri(PackageManager pm) throws NotFoundException {
282        if (mContextUriResource <= 0) throw new NotFoundException();
283        String packageName = mService.resolvePackageName;
284        ApplicationInfo applicationInfo = null;
285        if (packageName == null) {
286            packageName = mService.serviceInfo.packageName;
287            applicationInfo = mService.serviceInfo.applicationInfo;
288        }
289        String contextUriString = pm.getText(
290                packageName, mContextUriResource, applicationInfo).toString();
291        if (contextUriString == null) {
292            return null;
293        }
294        return Uri.parse(contextUriString);
295    }
296
297    /**
298     * Retrieves a title of the URI that specifies a link for further context about this wallpaper.
299     *
300     * @param pm An instance of {@link PackageManager} to retrieve the title.
301     * @return The title.
302     */
303    public CharSequence loadContextDescription(PackageManager pm) throws NotFoundException {
304        if (mContextDescriptionResource <= 0) throw new NotFoundException();
305        String packageName = mService.resolvePackageName;
306        ApplicationInfo applicationInfo = null;
307        if (packageName == null) {
308            packageName = mService.serviceInfo.packageName;
309            applicationInfo = mService.serviceInfo.applicationInfo;
310        }
311        return pm.getText(packageName, mContextDescriptionResource, applicationInfo).toString();
312    }
313
314    /**
315     * Queries whether any metadata should be shown when previewing the wallpaper. If this value is
316     * set to true, any component that shows a preview of this live wallpaper should also show
317     * accompanying information like {@link #loadLabel},
318     * {@link #loadDescription}, {@link #loadAuthor} and
319     * {@link #loadContextDescription(PackageManager)}, so the user gets to know further information
320     * about this wallpaper.
321     *
322     * @return Whether any metadata should be shown when previewing the wallpaper.
323     */
324    public boolean getShowMetadataInPreview() {
325        return mShowMetadataInPreview;
326    }
327
328    /**
329     * Return the class name of an activity that provides a settings UI for
330     * the wallpaper.  You can launch this activity be starting it with
331     * an {@link android.content.Intent} whose action is MAIN and with an
332     * explicit {@link android.content.ComponentName}
333     * composed of {@link #getPackageName} and the class name returned here.
334     *
335     * <p>A null will be returned if there is no settings activity associated
336     * with the wallpaper.
337     */
338    public String getSettingsActivity() {
339        return mSettingsActivityName;
340    }
341
342    public void dump(Printer pw, String prefix) {
343        pw.println(prefix + "Service:");
344        mService.dump(pw, prefix + "  ");
345        pw.println(prefix + "mSettingsActivityName=" + mSettingsActivityName);
346    }
347
348    @Override
349    public String toString() {
350        return "WallpaperInfo{" + mService.serviceInfo.name
351                + ", settings: "
352                + mSettingsActivityName + "}";
353    }
354
355    /**
356     * Used to package this object into a {@link Parcel}.
357     *
358     * @param dest The {@link Parcel} to be written.
359     * @param flags The flags used for parceling.
360     */
361    public void writeToParcel(Parcel dest, int flags) {
362        dest.writeString(mSettingsActivityName);
363        dest.writeInt(mThumbnailResource);
364        dest.writeInt(mAuthorResource);
365        dest.writeInt(mDescriptionResource);
366        dest.writeInt(mContextUriResource);
367        dest.writeInt(mContextDescriptionResource);
368        dest.writeInt(mShowMetadataInPreview ? 1 : 0);
369        mService.writeToParcel(dest, flags);
370    }
371
372    /**
373     * Used to make this class parcelable.
374     */
375    public static final Parcelable.Creator<WallpaperInfo> CREATOR = new Parcelable.Creator<WallpaperInfo>() {
376        public WallpaperInfo createFromParcel(Parcel source) {
377            return new WallpaperInfo(source);
378        }
379
380        public WallpaperInfo[] newArray(int size) {
381            return new WallpaperInfo[size];
382        }
383    };
384
385    public int describeContents() {
386        return 0;
387    }
388}
389