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