content: /*
   * Copyright (C) 2009 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.app;
  
  import android.annotation.Nullable;
  import android.annotation.SystemApi;
  import android.app.slice.Slice;
  import android.content.ComponentName;
  import android.content.Context;
  import android.content.pm.ApplicationInfo;
  import android.content.pm.PackageManager;
  import android.content.pm.PackageManager.NameNotFoundException;
  import android.content.pm.ResolveInfo;
  import android.content.pm.ServiceInfo;
  import android.content.res.Resources;
  import android.content.res.Resources.NotFoundException;
  import android.content.res.TypedArray;
  import android.content.res.XmlResourceParser;
  import android.graphics.drawable.Drawable;
  import android.net.Uri;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.service.wallpaper.WallpaperService;
  import android.util.AttributeSet;
  import android.util.Printer;
  import android.util.Xml;
  import android.view.SurfaceHolder;
  
  import org.xmlpull.v1.XmlPullParser;
  import org.xmlpull.v1.XmlPullParserException;
  
  import java.io.IOException;
  
  /**
   * This class is used to specify meta information of a wallpaper service.
   */
  public final class WallpaperInfo implements Parcelable {
      static final String TAG = "WallpaperInfo";
      
      /**
       * The Service that implements this wallpaper component.
       */
      final ResolveInfo mService;
      
      /**
       * The wallpaper setting activity's name, to
       * launch the setting activity of this wallpaper.
       */
      final String mSettingsActivityName;
  
      /**
       * Resource identifier for this wallpaper's thumbnail image.
       */
      final int mThumbnailResource;
  
      /**
       * Resource identifier for a string indicating the author of the wallpaper.
       */
      final int mAuthorResource;
  
      /**
       * Resource identifier for a string containing a short description of the wallpaper.
       */
      final int mDescriptionResource;
  
      final int mContextUriResource;
      final int mContextDescriptionResource;
      final boolean mShowMetadataInPreview;
      final boolean mSupportsAmbientMode;
      final String mSettingsSliceUri;
      final boolean mSupportMultipleDisplays;
  
      /**
       * Constructor.
       * 
       * @param context The Context in which we are parsing the wallpaper.
       * @param service The ResolveInfo returned from the package manager about
       * this wallpaper's component.
       */
      public WallpaperInfo(Context context, ResolveInfo service)
              throws XmlPullParserException, IOException {
          mService = service;
          ServiceInfo si = service.serviceInfo;
          
          final PackageManager pm = context.getPackageManager();
          XmlResourceParser parser = null;
          try {
              parser = si.loadXmlMetaData(pm, WallpaperService.SERVICE_META_DATA);
              if (parser == null) {
                  throw new XmlPullParserException("No "
                          + WallpaperService.SERVICE_META_DATA + " meta-data");
              }
          
              Resources res = pm.getResourcesForApplication(si.applicationInfo);
              
              AttributeSet attrs = Xml.asAttributeSet(parser);
              
              int type;
              while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                      && type != XmlPullParser.START_TAG) {
              }
              
              String nodeName = parser.getName();
              if (!"wallpaper".equals(nodeName)) {
                  throw new XmlPullParserException(
                          "Meta-data does not start with wallpaper tag");
              }
              
              TypedArray sa = res.obtainAttributes(attrs,
                      com.android.internal.R.styleable.Wallpaper);
              mSettingsActivityName = sa.getString(
                      com.android.internal.R.styleable.Wallpaper_settingsActivity);
              mThumbnailResource = sa.getResourceId(
                      com.android.internal.R.styleable.Wallpaper_thumbnail,
                      -1);
              mAuthorResource = sa.getResourceId(
                      com.android.internal.R.styleable.Wallpaper_author,
                      -1);
              mDescriptionResource = sa.getResourceId(
                      com.android.internal.R.styleable.Wallpaper_description,
                      -1);
              mContextUriResource = sa.getResourceId(
                      com.android.internal.R.styleable.Wallpaper_contextUri,
                      -1);
              mContextDescriptionResource = sa.getResourceId(
                      com.android.internal.R.styleable.Wallpaper_contextDescription,
                      -1);
              mShowMetadataInPreview = sa.getBoolean(
                      com.android.internal.R.styleable.Wallpaper_showMetadataInPreview,
                      false);
              mSupportsAmbientMode = sa.getBoolean(
                      com.android.internal.R.styleable.Wallpaper_supportsAmbientMode,
                      false);
              mSettingsSliceUri = sa.getString(
                      com.android.internal.R.styleable.Wallpaper_settingsSliceUri);
              mSupportMultipleDisplays = sa.getBoolean(
                      com.android.internal.R.styleable.Wallpaper_supportsMultipleDisplays,
                      false);
  
              sa.recycle();
          } catch (NameNotFoundException e) {
              throw new XmlPullParserException(
                      "Unable to create context for: " + si.packageName);
          } finally {
              if (parser != null) parser.close();
          }
      }
  
      WallpaperInfo(Parcel source) {
          mSettingsActivityName = source.readString();
          mThumbnailResource = source.readInt();
          mAuthorResource = source.readInt();
          mDescriptionResource = source.readInt();
          mContextUriResource = source.readInt();
          mContextDescriptionResource = source.readInt();
          mShowMetadataInPreview = source.readInt() != 0;
          mSupportsAmbientMode = source.readInt() != 0;
          mSettingsSliceUri = source.readString();
          mSupportMultipleDisplays = source.readInt() != 0;
          mService = ResolveInfo.CREATOR.createFromParcel(source);
      }
      
      /**
       * Return the .apk package that implements this wallpaper.
       */
      public String getPackageName() {
          return mService.serviceInfo.packageName;
      }
      
      /**
       * Return the class name of the service component that implements
       * this wallpaper.
       */
      public String getServiceName() {
          return mService.serviceInfo.name;
      }
  
      /**
       * Return the raw information about the Service implementing this
       * wallpaper.  Do not modify the returned object.
       */
      public ServiceInfo getServiceInfo() {
          return mService.serviceInfo;
      }
  
      /**
       * Return the component of the service that implements this wallpaper.
       */
      public ComponentName getComponent() {
          return new ComponentName(mService.serviceInfo.packageName,
                  mService.serviceInfo.name);
      }
      
      /**
       * Load the user-displayed label for this wallpaper.
       * 
       * @param pm Supply a PackageManager used to load the wallpaper's
       * resources.
       */
      public CharSequence loadLabel(PackageManager pm) {
          return mService.loadLabel(pm);
      }
      
      /**
       * Load the user-displayed icon for this wallpaper.
       * 
       * @param pm Supply a PackageManager used to load the wallpaper's
       * resources.
       */
      public Drawable loadIcon(PackageManager pm) {
          return mService.loadIcon(pm);
      }
      
      /**
       * Load the thumbnail image for this wallpaper.
       * 
       * @param pm Supply a PackageManager used to load the wallpaper's
       * resources.
       */
      public Drawable loadThumbnail(PackageManager pm) {
          if (mThumbnailResource < 0) return null;
  
          return pm.getDrawable(mService.serviceInfo.packageName,
                                mThumbnailResource,
                                mService.serviceInfo.applicationInfo);
      }
  
      /**
       * Return a string indicating the author(s) of this wallpaper.
       */
      public CharSequence loadAuthor(PackageManager pm) throws NotFoundException {
          if (mAuthorResource <= 0) throw new NotFoundException();
          String packageName = mService.resolvePackageName;
          ApplicationInfo applicationInfo = null;
          if (packageName == null) {
              packageName = mService.serviceInfo.packageName;
              applicationInfo = mService.serviceInfo.applicationInfo;
          }
          return pm.getText(packageName, mAuthorResource, applicationInfo);
      }
  
      /**
       * Return a brief summary of this wallpaper's behavior.
       */
      public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
          String packageName = mService.resolvePackageName;
          ApplicationInfo applicationInfo = null;
          if (packageName == null) {
              packageName = mService.serviceInfo.packageName;
              applicationInfo = mService.serviceInfo.applicationInfo;
          }
          if (mService.serviceInfo.descriptionRes != 0) {
              return pm.getText(packageName, mService.serviceInfo.descriptionRes,
                      applicationInfo);
              
          }
          if (mDescriptionResource <= 0) throw new NotFoundException();
          return pm.getText(packageName, mDescriptionResource,
                  mService.serviceInfo.applicationInfo);
      }
  
      /**
       * Returns an URI that specifies a link for further context about this wallpaper.
       *
       * @param pm An instance of {@link PackageManager} to retrieve the URI.
       * @return The URI.
       */
      public Uri loadContextUri(PackageManager pm) throws NotFoundException {
          if (mContextUriResource <= 0) throw new NotFoundException();
          String packageName = mService.resolvePackageName;
          ApplicationInfo applicationInfo = null;
          if (packageName == null) {
              packageName = mService.serviceInfo.packageName;
              applicationInfo = mService.serviceInfo.applicationInfo;
          }
          String contextUriString = pm.getText(
                  packageName, mContextUriResource, applicationInfo).toString();
          if (contextUriString == null) {
              return null;
          }
          return Uri.parse(contextUriString);
      }
  
      /**
       * Retrieves a title of the URI that specifies a link for further context about this wallpaper.
       *
       * @param pm An instance of {@link PackageManager} to retrieve the title.
       * @return The title.
       */
      public CharSequence loadContextDescription(PackageManager pm) throws NotFoundException {
          if (mContextDescriptionResource <= 0) throw new NotFoundException();
          String packageName = mService.resolvePackageName;
          ApplicationInfo applicationInfo = null;
          if (packageName == null) {
              packageName = mService.serviceInfo.packageName;
              applicationInfo = mService.serviceInfo.applicationInfo;
          }
          return pm.getText(packageName, mContextDescriptionResource, applicationInfo).toString();
      }
  
      /**
       * Queries whether any metadata should be shown when previewing the wallpaper. If this value is
       * set to true, any component that shows a preview of this live wallpaper should also show
       * accompanying information like {@link #loadLabel},
       * {@link #loadDescription}, {@link #loadAuthor} and
       * {@link #loadContextDescription(PackageManager)}, so the user gets to know further information
       * about this wallpaper.
       *
       * @return Whether any metadata should be shown when previewing the wallpaper.
       */
      public boolean getShowMetadataInPreview() {
          return mShowMetadataInPreview;
      }
  
      /**
       * Returns whether a wallpaper was optimized or not for ambient mode and can be drawn in there.
       *
       * @see WallpaperService.Engine#onAmbientModeChanged(boolean, boolean)
       * @see WallpaperService.Engine#isInAmbientMode()
       * @return {@code true} if wallpaper can draw when in ambient mode.
       * @hide
       */
      @SystemApi
      public boolean supportsAmbientMode() {
          return mSupportsAmbientMode;
      }
  
      /**
       * Return the class name of an activity that provides a settings UI for
       * the wallpaper.  You can launch this activity be starting it with
       * an {@link android.content.Intent} whose action is MAIN and with an
       * explicit {@link android.content.ComponentName}
       * composed of {@link #getPackageName} and the class name returned here.
       * 
       * <p>{@code null} will be returned if there is no settings activity associated
       * with the wallpaper.
       */
      public String getSettingsActivity() {
          return mSettingsActivityName;
      }
      
      /**
       * Returns an URI that provides a settings {@link Slice} for this wallpaper.
       * The wallpaper should implement a SliceProvider associated with this URI.
       * The system will display the Slice in the customization section while previewing the live
       * wallpaper. Because this URI is accessible to other apps, it is recommended to protect it
       * with the android.permission.BIND_WALLPAPER permission.
       *
       * <p>{@code null} will be returned if there is no settings Slice URI associated
       * with the wallpaper.
       *
       * @return The URI.
       */
      @Nullable
      public Uri getSettingsSliceUri() {
          if (mSettingsSliceUri == null) {
              return null;
          }
          return Uri.parse(mSettingsSliceUri);
      }
  
      /**
       * Returns whether this wallpaper service can support multiple engines to render on each surface
       * independently. An example use case is a multi-display set-up where the wallpaper service can
       * render surfaces to each of the connected displays.
       * <p>
       * This corresponds to the value {@link android.R.styleable#Wallpaper_supportsMultipleDisplays}
       * in the XML description of the wallpaper.
       * <p>
       * The default value is {@code false}.
       *
       * @see WallpaperService#onCreateEngine()
       * @see WallpaperService.Engine#onCreate(SurfaceHolder)
       * @return {@code true} if multiple engines can render independently on each surface.
       *
       * @attr ref android.R.styleable#Wallpaper_supportsMultipleDisplays
       */
      public boolean supportsMultipleDisplays() {
          return mSupportMultipleDisplays;
      }
  
      public void dump(Printer pw, String prefix) {
          pw.println(prefix + "Service:");
          mService.dump(pw, prefix + "  ");
          pw.println(prefix + "mSettingsActivityName=" + mSettingsActivityName);
      }
      
      @Override
      public String toString() {
          return "WallpaperInfo{" + mService.serviceInfo.name
                  + ", settings: "
                  + mSettingsActivityName + "}";
      }
  
      /**
       * Used to package this object into a {@link Parcel}.
       * 
       * @param dest The {@link Parcel} to be written.
       * @param flags The flags used for parceling.
       */
      public void writeToParcel(Parcel dest, int flags) {
          dest.writeString(mSettingsActivityName);
          dest.writeInt(mThumbnailResource);
          dest.writeInt(mAuthorResource);
          dest.writeInt(mDescriptionResource);
          dest.writeInt(mContextUriResource);
          dest.writeInt(mContextDescriptionResource);
          dest.writeInt(mShowMetadataInPreview ? 1 : 0);
          dest.writeInt(mSupportsAmbientMode ? 1 : 0);
          dest.writeString(mSettingsSliceUri);
          dest.writeInt(mSupportMultipleDisplays ? 1 : 0);
          mService.writeToParcel(dest, flags);
      }
  
      /**
       * Used to make this class parcelable.
       */
      public static final @android.annotation.NonNull Parcelable.Creator<WallpaperInfo> CREATOR = new Parcelable.Creator<WallpaperInfo>() {
          public WallpaperInfo createFromParcel(Parcel source) {
              return new WallpaperInfo(source);
          }
  
          public WallpaperInfo[] newArray(int size) {
              return new WallpaperInfo[size];
          }
      };
  
      public int describeContents() {
          return 0;
      }
  }
  