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 */ WallpaperInfo(Context context, ResolveInfo service)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 WallpaperInfo(Parcel source)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 */ getPackageName()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 */ getServiceName()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 */ getServiceInfo()196 public ServiceInfo getServiceInfo() { 197 return mService.serviceInfo; 198 } 199 200 /** 201 * Return the component of the service that implements this wallpaper. 202 */ getComponent()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 */ loadLabel(PackageManager pm)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 */ loadIcon(PackageManager pm)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 */ loadThumbnail(PackageManager pm)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 */ loadAuthor(PackageManager pm)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 */ loadDescription(PackageManager pm)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 */ loadContextUri(PackageManager pm)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 */ loadContextDescription(PackageManager pm)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 */ getShowMetadataInPreview()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 supportsAmbientMode()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 */ getSettingsActivity()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 getSettingsSliceUri()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 */ supportsMultipleDisplays()392 public boolean supportsMultipleDisplays() { 393 return mSupportMultipleDisplays; 394 } 395 dump(Printer pw, String prefix)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 toString()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 */ writeToParcel(Parcel dest, int flags)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 describeContents()442 public int describeContents() { 443 return 0; 444 } 445 } 446