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 boolean mShouldUseDefaultUnfoldTransition; 85 final String mSettingsSliceUri; 86 final boolean mSupportMultipleDisplays; 87 88 /** 89 * Constructor. 90 * 91 * @param context The Context in which we are parsing the wallpaper. 92 * @param service The ResolveInfo returned from the package manager about 93 * this wallpaper's component. 94 */ WallpaperInfo(Context context, ResolveInfo service)95 public WallpaperInfo(Context context, ResolveInfo service) 96 throws XmlPullParserException, IOException { 97 mService = service; 98 ServiceInfo si = service.serviceInfo; 99 100 final PackageManager pm = context.getPackageManager(); 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 mSettingsActivityName = sa.getString( 127 com.android.internal.R.styleable.Wallpaper_settingsActivity); 128 mThumbnailResource = sa.getResourceId( 129 com.android.internal.R.styleable.Wallpaper_thumbnail, 130 -1); 131 mAuthorResource = sa.getResourceId( 132 com.android.internal.R.styleable.Wallpaper_author, 133 -1); 134 mDescriptionResource = sa.getResourceId( 135 com.android.internal.R.styleable.Wallpaper_description, 136 -1); 137 mContextUriResource = sa.getResourceId( 138 com.android.internal.R.styleable.Wallpaper_contextUri, 139 -1); 140 mContextDescriptionResource = sa.getResourceId( 141 com.android.internal.R.styleable.Wallpaper_contextDescription, 142 -1); 143 mShowMetadataInPreview = sa.getBoolean( 144 com.android.internal.R.styleable.Wallpaper_showMetadataInPreview, 145 false); 146 mSupportsAmbientMode = sa.getBoolean( 147 com.android.internal.R.styleable.Wallpaper_supportsAmbientMode, 148 false); 149 mShouldUseDefaultUnfoldTransition = sa.getBoolean( 150 com.android.internal.R.styleable 151 .Wallpaper_shouldUseDefaultUnfoldTransition, true); 152 mSettingsSliceUri = sa.getString( 153 com.android.internal.R.styleable.Wallpaper_settingsSliceUri); 154 mSupportMultipleDisplays = sa.getBoolean( 155 com.android.internal.R.styleable.Wallpaper_supportsMultipleDisplays, 156 false); 157 158 sa.recycle(); 159 } catch (NameNotFoundException e) { 160 throw new XmlPullParserException( 161 "Unable to create context for: " + si.packageName); 162 } finally { 163 if (parser != null) parser.close(); 164 } 165 } 166 WallpaperInfo(Parcel source)167 WallpaperInfo(Parcel source) { 168 mSettingsActivityName = source.readString(); 169 mThumbnailResource = source.readInt(); 170 mAuthorResource = source.readInt(); 171 mDescriptionResource = source.readInt(); 172 mContextUriResource = source.readInt(); 173 mContextDescriptionResource = source.readInt(); 174 mShowMetadataInPreview = source.readInt() != 0; 175 mSupportsAmbientMode = source.readInt() != 0; 176 mSettingsSliceUri = source.readString(); 177 mSupportMultipleDisplays = source.readInt() != 0; 178 mShouldUseDefaultUnfoldTransition = source.readInt() != 0; 179 mService = ResolveInfo.CREATOR.createFromParcel(source); 180 } 181 182 /** 183 * Return the .apk package that implements this wallpaper. 184 */ getPackageName()185 public String getPackageName() { 186 return mService.serviceInfo.packageName; 187 } 188 189 /** 190 * Return the class name of the service component that implements 191 * this wallpaper. 192 */ getServiceName()193 public String getServiceName() { 194 return mService.serviceInfo.name; 195 } 196 197 /** 198 * Return the raw information about the Service implementing this 199 * wallpaper. Do not modify the returned object. 200 */ getServiceInfo()201 public ServiceInfo getServiceInfo() { 202 return mService.serviceInfo; 203 } 204 205 /** 206 * Return the component of the service that implements this wallpaper. 207 */ getComponent()208 public ComponentName getComponent() { 209 return new ComponentName(mService.serviceInfo.packageName, 210 mService.serviceInfo.name); 211 } 212 213 /** 214 * Load the user-displayed label for this wallpaper. 215 * 216 * @param pm Supply a PackageManager used to load the wallpaper's 217 * resources. 218 */ loadLabel(PackageManager pm)219 public CharSequence loadLabel(PackageManager pm) { 220 return mService.loadLabel(pm); 221 } 222 223 /** 224 * Load the user-displayed icon for this wallpaper. 225 * 226 * @param pm Supply a PackageManager used to load the wallpaper's 227 * resources. 228 */ loadIcon(PackageManager pm)229 public Drawable loadIcon(PackageManager pm) { 230 return mService.loadIcon(pm); 231 } 232 233 /** 234 * Load the thumbnail image for this wallpaper. 235 * 236 * @param pm Supply a PackageManager used to load the wallpaper's 237 * resources. 238 */ loadThumbnail(PackageManager pm)239 public Drawable loadThumbnail(PackageManager pm) { 240 if (mThumbnailResource < 0) return null; 241 242 return pm.getDrawable(mService.serviceInfo.packageName, 243 mThumbnailResource, 244 mService.serviceInfo.applicationInfo); 245 } 246 247 /** 248 * Return a string indicating the author(s) of this wallpaper. 249 */ loadAuthor(PackageManager pm)250 public CharSequence loadAuthor(PackageManager pm) throws NotFoundException { 251 if (mAuthorResource <= 0) throw new NotFoundException(); 252 String packageName = mService.resolvePackageName; 253 ApplicationInfo applicationInfo = null; 254 if (packageName == null) { 255 packageName = mService.serviceInfo.packageName; 256 applicationInfo = mService.serviceInfo.applicationInfo; 257 } 258 return pm.getText(packageName, mAuthorResource, applicationInfo); 259 } 260 261 /** 262 * Return a brief summary of this wallpaper's behavior. 263 */ loadDescription(PackageManager pm)264 public CharSequence loadDescription(PackageManager pm) throws NotFoundException { 265 String packageName = mService.resolvePackageName; 266 ApplicationInfo applicationInfo = null; 267 if (packageName == null) { 268 packageName = mService.serviceInfo.packageName; 269 applicationInfo = mService.serviceInfo.applicationInfo; 270 } 271 if (mService.serviceInfo.descriptionRes != 0) { 272 return pm.getText(packageName, mService.serviceInfo.descriptionRes, 273 applicationInfo); 274 275 } 276 if (mDescriptionResource <= 0) throw new NotFoundException(); 277 return pm.getText(packageName, mDescriptionResource, 278 mService.serviceInfo.applicationInfo); 279 } 280 281 /** 282 * Returns an URI that specifies a link for further context about this wallpaper. 283 * 284 * @param pm An instance of {@link PackageManager} to retrieve the URI. 285 * @return The URI. 286 */ loadContextUri(PackageManager pm)287 public Uri loadContextUri(PackageManager pm) throws NotFoundException { 288 if (mContextUriResource <= 0) throw new NotFoundException(); 289 String packageName = mService.resolvePackageName; 290 ApplicationInfo applicationInfo = null; 291 if (packageName == null) { 292 packageName = mService.serviceInfo.packageName; 293 applicationInfo = mService.serviceInfo.applicationInfo; 294 } 295 CharSequence contextUriCharSequence = pm.getText( 296 packageName, mContextUriResource, applicationInfo); 297 if (contextUriCharSequence == null) { 298 return null; 299 } 300 return Uri.parse(contextUriCharSequence.toString()); 301 } 302 303 /** 304 * Retrieves a title of the URI that specifies a link for further context about this wallpaper. 305 * 306 * @param pm An instance of {@link PackageManager} to retrieve the title. 307 * @return The title. 308 */ loadContextDescription(PackageManager pm)309 public CharSequence loadContextDescription(PackageManager pm) throws NotFoundException { 310 if (mContextDescriptionResource <= 0) throw new NotFoundException(); 311 String packageName = mService.resolvePackageName; 312 ApplicationInfo applicationInfo = null; 313 if (packageName == null) { 314 packageName = mService.serviceInfo.packageName; 315 applicationInfo = mService.serviceInfo.applicationInfo; 316 } 317 return pm.getText(packageName, mContextDescriptionResource, applicationInfo).toString(); 318 } 319 320 /** 321 * Queries whether any metadata should be shown when previewing the wallpaper. If this value is 322 * set to true, any component that shows a preview of this live wallpaper should also show 323 * accompanying information like {@link #loadLabel}, 324 * {@link #loadDescription}, {@link #loadAuthor} and 325 * {@link #loadContextDescription(PackageManager)}, so the user gets to know further information 326 * about this wallpaper. 327 * 328 * @return Whether any metadata should be shown when previewing the wallpaper. 329 */ getShowMetadataInPreview()330 public boolean getShowMetadataInPreview() { 331 return mShowMetadataInPreview; 332 } 333 334 /** 335 * Returns whether a wallpaper was optimized or not for ambient mode and can be drawn in there. 336 * 337 * @see WallpaperService.Engine#onAmbientModeChanged(boolean, boolean) 338 * @see WallpaperService.Engine#isInAmbientMode() 339 * @return {@code true} if wallpaper can draw when in ambient mode. 340 * @hide 341 */ 342 @SystemApi supportsAmbientMode()343 public boolean supportsAmbientMode() { 344 return mSupportsAmbientMode; 345 } 346 347 /** 348 * Return the class name of an activity that provides a settings UI for 349 * the wallpaper. You can launch this activity be starting it with 350 * an {@link android.content.Intent} whose action is MAIN and with an 351 * explicit {@link android.content.ComponentName} 352 * composed of {@link #getPackageName} and the class name returned here. 353 * 354 * <p>{@code null} will be returned if there is no settings activity associated 355 * with the wallpaper. 356 */ getSettingsActivity()357 public String getSettingsActivity() { 358 return mSettingsActivityName; 359 } 360 361 /** 362 * Returns an URI that provides a settings {@link Slice} for this wallpaper. 363 * The wallpaper should implement a SliceProvider associated with this URI. 364 * The system will display the Slice in the customization section while previewing the live 365 * wallpaper. Because this URI is accessible to other apps, it is recommended to protect it 366 * with the android.permission.BIND_WALLPAPER permission. 367 * 368 * <p>{@code null} will be returned if there is no settings Slice URI associated 369 * with the wallpaper. 370 * 371 * @return The URI. 372 */ 373 @Nullable getSettingsSliceUri()374 public Uri getSettingsSliceUri() { 375 if (mSettingsSliceUri == null) { 376 return null; 377 } 378 return Uri.parse(mSettingsSliceUri); 379 } 380 381 /** 382 * Returns whether this wallpaper service can support multiple engines to render on each surface 383 * independently. An example use case is a multi-display set-up where the wallpaper service can 384 * render surfaces to each of the connected displays. 385 * <p> 386 * This corresponds to the value {@link android.R.styleable#Wallpaper_supportsMultipleDisplays} 387 * in the XML description of the wallpaper. 388 * <p> 389 * The default value is {@code false}. 390 * 391 * @see WallpaperService#onCreateEngine() 392 * @see WallpaperService.Engine#onCreate(SurfaceHolder) 393 * @return {@code true} if multiple engines can render independently on each surface. 394 * 395 * @attr ref android.R.styleable#Wallpaper_supportsMultipleDisplays 396 */ supportsMultipleDisplays()397 public boolean supportsMultipleDisplays() { 398 return mSupportMultipleDisplays; 399 } 400 401 /** 402 * Returns whether this wallpaper should receive default zooming updates when the device 403 * changes its state (e.g. when folding or unfolding a foldable device). 404 * If set to false the wallpaper will not receive zoom events when changing the device state, 405 * so it can implement its own transition instead. 406 * <p> 407 * This corresponds to the value {@link 408 * android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition} in the 409 * XML description of the wallpaper. 410 * <p> 411 * The default value is {@code true}. 412 * 413 * @see android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition 414 * @return {@code true} if wallpaper should receive default device state change 415 * transition updates 416 * 417 * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition 418 */ shouldUseDefaultUnfoldTransition()419 public boolean shouldUseDefaultUnfoldTransition() { 420 return mShouldUseDefaultUnfoldTransition; 421 } 422 dump(Printer pw, String prefix)423 public void dump(Printer pw, String prefix) { 424 pw.println(prefix + "Service:"); 425 mService.dump(pw, prefix + " "); 426 pw.println(prefix + "mSettingsActivityName=" + mSettingsActivityName); 427 } 428 429 @Override toString()430 public String toString() { 431 return "WallpaperInfo{" + mService.serviceInfo.name 432 + ", settings: " 433 + mSettingsActivityName + "}"; 434 } 435 436 /** 437 * Used to package this object into a {@link Parcel}. 438 * 439 * @param dest The {@link Parcel} to be written. 440 * @param flags The flags used for parceling. 441 */ writeToParcel(Parcel dest, int flags)442 public void writeToParcel(Parcel dest, int flags) { 443 dest.writeString(mSettingsActivityName); 444 dest.writeInt(mThumbnailResource); 445 dest.writeInt(mAuthorResource); 446 dest.writeInt(mDescriptionResource); 447 dest.writeInt(mContextUriResource); 448 dest.writeInt(mContextDescriptionResource); 449 dest.writeInt(mShowMetadataInPreview ? 1 : 0); 450 dest.writeInt(mSupportsAmbientMode ? 1 : 0); 451 dest.writeString(mSettingsSliceUri); 452 dest.writeInt(mSupportMultipleDisplays ? 1 : 0); 453 dest.writeInt(mShouldUseDefaultUnfoldTransition ? 1 : 0); 454 mService.writeToParcel(dest, flags); 455 } 456 457 /** 458 * Used to make this class parcelable. 459 */ 460 public static final @android.annotation.NonNull Parcelable.Creator<WallpaperInfo> CREATOR = new Parcelable.Creator<WallpaperInfo>() { 461 public WallpaperInfo createFromParcel(Parcel source) { 462 return new WallpaperInfo(source); 463 } 464 465 public WallpaperInfo[] newArray(int size) { 466 return new WallpaperInfo[size]; 467 } 468 }; 469 describeContents()470 public int describeContents() { 471 return 0; 472 } 473 } 474