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