diff options
12 files changed, 441 insertions, 77 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 8bd4367dece8..76d9eea05cbe 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9677,9 +9677,11 @@ package android.app.wallpaper { method @Nullable public String getId(); method @Nullable public android.net.Uri getThumbnail(); method @Nullable public CharSequence getTitle(); + method @NonNull public static android.app.wallpaper.WallpaperDescription readFromStream(@NonNull java.io.InputStream) throws java.io.IOException; method @NonNull public android.app.wallpaper.WallpaperDescription.Builder toBuilder(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @Nullable public static final android.os.Parcelable.Creator<android.app.wallpaper.WallpaperDescription> CREATOR; + method public void writeToStream(@NonNull java.io.OutputStream) throws java.io.IOException; + field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpaper.WallpaperDescription> CREATOR; } public static final class WallpaperDescription.Builder { @@ -42085,6 +42087,7 @@ package android.service.wallpaper { ctor public WallpaperService(); method public final android.os.IBinder onBind(android.content.Intent); method @MainThread public abstract android.service.wallpaper.WallpaperService.Engine onCreateEngine(); + method @FlaggedApi("android.app.live_wallpaper_content_handling") @MainThread @Nullable public android.service.wallpaper.WallpaperService.Engine onCreateEngine(@NonNull android.app.wallpaper.WallpaperDescription); field public static final String SERVICE_INTERFACE = "android.service.wallpaper.WallpaperService"; field public static final String SERVICE_META_DATA = "android.service.wallpaper"; } @@ -42100,6 +42103,7 @@ package android.service.wallpaper { method public boolean isPreview(); method public boolean isVisible(); method public void notifyColorsChanged(); + method @FlaggedApi("android.app.live_wallpaper_content_handling") @Nullable public android.app.wallpaper.WallpaperDescription onApplyWallpaper(int); method @MainThread public void onApplyWindowInsets(android.view.WindowInsets); method @MainThread public android.os.Bundle onCommand(String, int, int, int, android.os.Bundle, boolean); method @MainThread @Nullable public android.app.WallpaperColors onComputeColors(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index bba52f584c97..9e96f2894e1f 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1264,8 +1264,10 @@ package android.app { public class WallpaperManager { method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void clearWallpaper(int, int); method @FloatRange(from=0.0f, to=1.0f) @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT) public float getWallpaperDimAmount(); + method @FlaggedApi("android.app.live_wallpaper_content_handling") @Nullable @RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL) public android.app.wallpaper.WallpaperInstance getWallpaperInstance(int); method public void setDisplayOffset(android.os.IBinder, int, int); method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName); + method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(allOf={android.Manifest.permission.SET_WALLPAPER_COMPONENT, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public boolean setWallpaperComponentWithDescription(@NonNull android.app.wallpaper.WallpaperDescription, int); method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponentWithFlags(@NonNull android.content.ComponentName, int); method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT) public void setWallpaperDimAmount(@FloatRange(from=0.0f, to=1.0f) float); } diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 5acb9b5cf9ae..f693e9ba11ec 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -24,6 +24,8 @@ import android.os.ParcelFileDescriptor; import android.app.IWallpaperManagerCallback; import android.app.ILocalWallpaperColorConsumer; import android.app.WallpaperInfo; +import android.app.wallpaper.WallpaperDescription; +import android.app.wallpaper.WallpaperInstance; import android.content.ComponentName; import android.app.WallpaperColors; @@ -61,8 +63,8 @@ interface IWallpaperManager { /** * Set the live wallpaper. */ - void setWallpaperComponentChecked(in ComponentName name, in String callingPackage, int which, - int userId); + void setWallpaperComponentChecked(in WallpaperDescription description, in String callingPackage, + int which, int userId); /** * Set the live wallpaper. This only affects the system wallpaper. @@ -129,6 +131,13 @@ interface IWallpaperManager { */ WallpaperInfo getWallpaperInfoWithFlags(int which, int userId); + /** + * Return the instance information about the wallpaper described by `which`, or null if lock + * screen is requested and it is the same as home. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL)") + WallpaperInstance getWallpaperInstance(int which, int userId); + /** * Return a file descriptor for the file that contains metadata about the given user's * wallpaper. diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 014e4660f944..140a7f839041 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -21,10 +21,12 @@ import static android.Manifest.permission.READ_WALLPAPER_INTERNAL; import static android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; +import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING; import static com.android.window.flags.Flags.FLAG_MULTI_CROP; import static com.android.window.flags.Flags.multiCrop; +import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -39,6 +41,8 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UiContext; import android.app.compat.CompatChanges; +import android.app.wallpaper.WallpaperDescription; +import android.app.wallpaper.WallpaperInstance; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; @@ -2023,6 +2027,34 @@ public class WallpaperManager { } /** + * Returns the description of the designated wallpaper. Returns null if the lock screen + * wallpaper is requested lock screen wallpaper is not set. + + * @param which Specifies wallpaper to request (home or lock). + * @throws IllegalArgumentException if {@code which} is not exactly one of + * {{@link #FLAG_SYSTEM},{@link #FLAG_LOCK}}. + * + * @hide + */ + @Nullable + @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING) + @RequiresPermission(READ_WALLPAPER_INTERNAL) + @SystemApi + public WallpaperInstance getWallpaperInstance(@SetWallpaperFlags int which) { + checkExactlyOneWallpaperFlagSet(which); + try { + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + throw new RuntimeException(new DeadSystemException()); + } else { + return sGlobals.mService.getWallpaperInstance(which, mContext.getUserId()); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Get an open, readable file descriptor for the file that contains metadata about the * context user's wallpaper. * @@ -2955,15 +2987,66 @@ public class WallpaperManager { * * @hide */ - @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) + @RequiresPermission(allOf = {android.Manifest.permission.SET_WALLPAPER_COMPONENT, + Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional = true) public boolean setWallpaperComponentWithFlags(@NonNull ComponentName name, @SetWallpaperFlags int which, int userId) { + WallpaperDescription description = new WallpaperDescription.Builder().setComponent( + name).build(); + return setWallpaperComponentWithDescription(description, which, userId); + } + + /** + * Set the implementation of {@link android.service.wallpaper.WallpaperService} used to render + * wallpaper, along with associated metadata. + * + * <p>This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT + * permission. The caller must hold the INTERACT_ACROSS_USERS_FULL permission to change + * another user's wallpaper. + * </p> + * + * @param description wallpaper component and metadata to set + * @param which Specifies wallpaper destination (home and/or lock). + * @return true on success, otherwise false + * + * @hide + */ + @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING) + @SystemApi + @RequiresPermission(allOf = {android.Manifest.permission.SET_WALLPAPER_COMPONENT, + Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional = true) + public boolean setWallpaperComponentWithDescription(@NonNull WallpaperDescription description, + @SetWallpaperFlags int which) { + return setWallpaperComponentWithDescription(description, which, mContext.getUserId()); + } + + /** + * Set the implementation of {@link android.service.wallpaper.WallpaperService} used to render + * wallpaper, along with associated metadata. + * + * <p>This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT + * permission. The caller must hold the INTERACT_ACROSS_USERS_FULL permission to change + * another user's wallpaper. + * </p> + * + * @param description wallpaper component and metadata to set + * @param which Specifies wallpaper destination (home and/or lock). + * @param userId User for whom the component should be set. + * @return true on success, otherwise false + * + * @hide + */ + @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING) + @RequiresPermission(allOf = {android.Manifest.permission.SET_WALLPAPER_COMPONENT, + Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional = true) + public boolean setWallpaperComponentWithDescription(@NonNull WallpaperDescription description, + @SetWallpaperFlags int which, int userId) { if (sGlobals.mService == null) { Log.w(TAG, "WallpaperManagerService not running"); throw new RuntimeException(new DeadSystemException()); } try { - sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName(), + sGlobals.mService.setWallpaperComponentChecked(description, mContext.getOpPackageName(), which, userId); return true; } catch (RemoteException e) { diff --git a/core/java/android/app/wallpaper/WallpaperDescription.java b/core/java/android/app/wallpaper/WallpaperDescription.java index dedcb48f3ad7..c3d6340be41f 100644 --- a/core/java/android/app/wallpaper/WallpaperDescription.java +++ b/core/java/android/app/wallpaper/WallpaperDescription.java @@ -18,6 +18,8 @@ package android.app.wallpaper; import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING; +import static java.nio.charset.StandardCharsets.UTF_8; + import android.annotation.FlaggedApi; import android.app.WallpaperInfo; import android.content.ComponentName; @@ -29,6 +31,7 @@ import android.text.Html; import android.text.Spanned; import android.text.SpannedString; import android.util.Log; +import android.util.Xml; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -40,6 +43,8 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -149,6 +154,46 @@ public final class WallpaperDescription implements Parcelable { return Objects.hash(mComponent, mId); } + ////// Stream read/write + + /** + * Writes the content of the {@link WallpaperDescription} to a {@link OutputStream}. + * + * <p>The content can be read by {@link #readFromStream}. This method is intended for use by + * trusted apps only, and the format is not guaranteed to be stable.</p> + */ + public void writeToStream(@NonNull OutputStream outputStream) throws IOException { + TypedXmlSerializer serializer = Xml.newFastSerializer(); + serializer.setOutput(outputStream, UTF_8.name()); + serializer.startTag(null, "description"); + try { + saveToXml(serializer); + } catch (XmlPullParserException e) { + throw new IOException(e); + } + serializer.endTag(null, "description"); + serializer.flush(); + } + + /** + * Reads a {@link PersistableBundle} from an {@link InputStream}. + * + * <p>The stream must be generated by {@link #writeToStream}. This method is intended for use by + * trusted apps only, and the format is not guaranteed to be stable.</p> + */ + @NonNull + public static WallpaperDescription readFromStream(@NonNull InputStream inputStream) + throws IOException { + try { + TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setInput(inputStream, UTF_8.name()); + parser.next(); + return WallpaperDescription.restoreFromXml(parser); + } catch (XmlPullParserException e) { + throw new IOException(e); + } + } + ////// XML storage /** @hide */ @@ -255,7 +300,7 @@ public final class WallpaperDescription implements Parcelable { mContent = PersistableBundle.CREATOR.createFromParcel(in); } - @Nullable + @NonNull public static final Creator<WallpaperDescription> CREATOR = new Creator<>() { @Override public WallpaperDescription createFromParcel(Parcel source) { diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl index f1ae22eca873..e9e26466339c 100644 --- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl +++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl @@ -22,6 +22,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.view.MotionEvent; import android.view.SurfaceControl; +import android.app.wallpaper.WallpaperDescription; import android.os.Bundle; /** @@ -50,4 +51,5 @@ interface IWallpaperEngine { SurfaceControl mirrorSurfaceControl(); oneway void applyDimming(float dimAmount); oneway void setWallpaperFlags(int which); + @nullable WallpaperDescription onApplyWallpaper(int which); } diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl index 3262f3a9fdfb..f76e6cee13f0 100644 --- a/core/java/android/service/wallpaper/IWallpaperService.aidl +++ b/core/java/android/service/wallpaper/IWallpaperService.aidl @@ -17,6 +17,7 @@ package android.service.wallpaper; import android.app.WallpaperInfo; +import android.app.wallpaper.WallpaperDescription; import android.graphics.Rect; import android.service.wallpaper.IWallpaperConnection; @@ -27,6 +28,6 @@ oneway interface IWallpaperService { void attach(IWallpaperConnection connection, IBinder windowToken, int windowType, boolean isPreview, int reqWidth, int reqHeight, in Rect padding, int displayId, int which, - in WallpaperInfo info); + in WallpaperInfo info, in @nullable WallpaperDescription description); void detach(IBinder windowToken); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 2ab16e91d987..f839a63c214f 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -16,6 +16,7 @@ package android.service.wallpaper; +import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING; import static android.app.WallpaperManager.COMMAND_FREEZE; import static android.app.WallpaperManager.COMMAND_UNFREEZE; import static android.app.WallpaperManager.SetWallpaperFlags; @@ -50,6 +51,7 @@ import android.app.WallpaperColors; import android.app.WallpaperInfo; import android.app.WallpaperManager; import android.app.compat.CompatChanges; +import android.app.wallpaper.WallpaperDescription; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; @@ -922,6 +924,24 @@ public abstract class WallpaperService extends Service { } /** + * Called when the wallpaper preview rendered by this engine is about to be persisted as + * a selected wallpaper. The returned WallpaperDescription (if any) will be persisted by + * the system and passed into subsequent calls to + * {@link WallpaperService#onCreateEngine(WallpaperDescription)}. This allows the Engine + * to perform any necessary bookkeeping before a wallpaper being previewed is set on + * the device, and update the description if necessary. + * + * @param which Specifies wallpaper destination: home, lock, or both + * @return the description of the applied wallpaper, or {@code null} if description is + * unchanged + */ + @Nullable + @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING) + public WallpaperDescription onApplyWallpaper(@SetWallpaperFlags int which) { + return null; + } + + /** * Notifies the engine that wallpaper colors changed significantly. * This will trigger a {@link #onComputeColors()} call. */ @@ -2449,6 +2469,7 @@ public abstract class WallpaperService extends Service { final Display mDisplay; final WallpaperManager mWallpaperManager; @Nullable final WallpaperInfo mInfo; + @NonNull final WallpaperDescription mDescription; Engine mEngine; @SetWallpaperFlags int mWhich; @@ -2456,7 +2477,8 @@ public abstract class WallpaperService extends Service { IWallpaperEngineWrapper(WallpaperService service, IWallpaperConnection conn, IBinder windowToken, int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding, - int displayId, @SetWallpaperFlags int which, @Nullable WallpaperInfo info) { + int displayId, @SetWallpaperFlags int which, @Nullable WallpaperInfo info, + @NonNull WallpaperDescription description) { mWallpaperManager = getSystemService(WallpaperManager.class); mCaller = new HandlerCaller(service, service.onProvideEngineLooper(), this, true); mConnection = conn; @@ -2469,6 +2491,7 @@ public abstract class WallpaperService extends Service { mDisplayId = displayId; mWhich = which; mInfo = info; + mDescription = description; // Create a display context before onCreateEngine. mDisplayManager = getSystemService(DisplayManager.class); @@ -2593,9 +2616,14 @@ public abstract class WallpaperService extends Service { return mEngine == null ? null : SurfaceControl.mirrorSurface(mEngine.mSurfaceControl); } + @Nullable + public WallpaperDescription onApplyWallpaper(@SetWallpaperFlags int which) { + return mEngine != null ? mEngine.onApplyWallpaper(which) : null; + } + private void doAttachEngine() { Trace.beginSection("WPMS.onCreateEngine"); - Engine engine = onCreateEngine(); + Engine engine = onCreateEngine(mDescription); Trace.endSection(); mEngine = engine; Trace.beginSection("WPMS.mConnection.attachEngine-" + mDisplayId); @@ -2804,11 +2832,13 @@ public abstract class WallpaperService extends Service { @Override public void attach(IWallpaperConnection conn, IBinder windowToken, int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding, - int displayId, @SetWallpaperFlags int which, @Nullable WallpaperInfo info) { + int displayId, @SetWallpaperFlags int which, WallpaperInfo info, + @NonNull WallpaperDescription description) { Trace.beginSection("WPMS.ServiceWrapper.attach"); IWallpaperEngineWrapper engineWrapper = new IWallpaperEngineWrapper(mTarget, conn, windowToken, windowType, - isPreview, reqWidth, reqHeight, padding, displayId, which, info); + isPreview, reqWidth, reqHeight, padding, displayId, which, info, + description); synchronized (mActiveEngines) { mActiveEngines.put(windowToken, engineWrapper); } @@ -2883,6 +2913,19 @@ public abstract class WallpaperService extends Service { @MainThread public abstract Engine onCreateEngine(); + /** + * Creates a new engine instance to show the given content. See also {@link #onCreateEngine()}. + * + * @param description content to display + * @return the rendering engine + */ + @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING) + @MainThread + @Nullable + public Engine onCreateEngine(@NonNull WallpaperDescription description) { + return onCreateEngine(); + } + @Override protected void dump(FileDescriptor fd, PrintWriter out, String[] args) { out.print("State of wallpaper "); out.print(this); out.println(":"); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java index c8d5a0332a4f..f09b0a1c6e41 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperData.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java @@ -16,6 +16,7 @@ package com.android.server.wallpaper; +import static android.app.Flags.liveWallpaperContentHandling; import static android.app.WallpaperManager.FLAG_LOCK; import static android.app.WallpaperManager.ORIENTATION_UNKNOWN; @@ -25,6 +26,7 @@ import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_CROP; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG; import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir; +import android.annotation.NonNull; import android.app.IWallpaperManagerCallback; import android.app.WallpaperColors; import android.app.WallpaperManager.ScreenOrientation; @@ -149,6 +151,7 @@ class WallpaperData { UNKNOWN, CONNECT_LOCKED, CONNECTION_TRY_TO_REBIND, + FALLBACK_DEFAULT_MISSING, INITIALIZE_FALLBACK, PACKAGE_UPDATE_FINISHED, RESTORE_SETTINGS_LIVE_FAILURE, @@ -183,7 +186,7 @@ class WallpaperData { int mOrientationWhenSet = ORIENTATION_UNKNOWN; /** Description of the current wallpaper */ - private WallpaperDescription mDescription; + private WallpaperDescription mDescription = new WallpaperDescription.Builder().build(); WallpaperData(int userId, @SetWallpaperFlags int wallpaperType) { this.userId = userId; @@ -212,6 +215,9 @@ class WallpaperData { this.primaryColors = source.primaryColors; this.mWallpaperDimAmount = source.mWallpaperDimAmount; this.connection = source.connection; + if (liveWallpaperContentHandling()) { + this.setDescription(source.getDescription()); + } if (this.connection != null) { this.connection.mWallpaper = this; } @@ -236,19 +242,37 @@ class WallpaperData { return result; } - ComponentName getComponent() { - return mWallpaperComponent; + @NonNull ComponentName getComponent() { + if (liveWallpaperContentHandling()) { + return mDescription.getComponent(); + } else { + return mWallpaperComponent; + } } - void setComponent(ComponentName componentName) { + void setComponent(@NonNull ComponentName componentName) { + if (liveWallpaperContentHandling()) { + throw new IllegalStateException( + "Use \"setDescription\" when content handling is enabled"); + } this.mWallpaperComponent = componentName; } - WallpaperDescription getDescription() { + @NonNull WallpaperDescription getDescription() { return mDescription; } - void setDescription(WallpaperDescription description) { + void setDescription(@NonNull WallpaperDescription description) { + if (!liveWallpaperContentHandling()) { + throw new IllegalStateException( + "Use \"setContent\" when content handling is disabled"); + } + if (description == null) { + throw new IllegalArgumentException("WallpaperDescription must not be null"); + } + if (description.getComponent() == null) { + throw new IllegalArgumentException("WallpaperDescription component must not be null"); + } this.mDescription = description; } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java index cf76bf05ab19..969aea24f9e9 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java @@ -180,15 +180,8 @@ public class WallpaperDataParser { success = true; } catch (FileNotFoundException e) { Slog.w(TAG, "no current wallpaper -- first boot?"); - } catch (NullPointerException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); - } catch (NumberFormatException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); - } catch (XmlPullParserException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); - } catch (IOException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); - } catch (IndexOutOfBoundsException e) { + } catch (NullPointerException | NumberFormatException | XmlPullParserException + | IOException | IndexOutOfBoundsException e) { Slog.w(TAG, "failed parsing " + file + " " + e); } IoUtils.closeQuietly(stream); @@ -256,12 +249,13 @@ public class WallpaperDataParser { } ComponentName comp = parseComponentName(parser); - if (removeNextWallpaperComponent()) { - wallpaperToParse.setComponent(comp); - } else { - wallpaperToParse.nextWallpaperComponent = comp; + if (!liveWallpaperContentHandling()) { + if (removeNextWallpaperComponent()) { + wallpaperToParse.setComponent(comp); + } else { + wallpaperToParse.nextWallpaperComponent = comp; + } } - if (multiCrop()) { parseWallpaperAttributes(parser, wallpaperToParse, keepDimensionHints); } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index da9a67640f77..5cff37a36656 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE; import static android.Manifest.permission.READ_WALLPAPER_INTERNAL; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.app.Flags.fixWallpaperChanged; +import static android.app.Flags.liveWallpaperContentHandling; import static android.app.Flags.removeNextWallpaperComponent; import static android.app.WallpaperManager.COMMAND_REAPPLY; import static android.app.WallpaperManager.FLAG_LOCK; @@ -66,6 +67,8 @@ import android.app.WallpaperInfo; import android.app.WallpaperManager; import android.app.WallpaperManager.SetWallpaperFlags; import android.app.admin.DevicePolicyManagerInternal; +import android.app.wallpaper.WallpaperDescription; +import android.app.wallpaper.WallpaperInstance; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -849,16 +852,24 @@ public class WallpaperManagerService extends IWallpaperManager.Stub final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(mDisplayId); try { - connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false, - wpdData.mWidth, wpdData.mHeight, - wpdData.mPadding, mDisplayId, wallpaper.mWhich, connection.mInfo); + if (liveWallpaperContentHandling()) { + connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false, + wpdData.mWidth, wpdData.mHeight, + wpdData.mPadding, mDisplayId, wallpaper.mWhich, connection.mInfo, + wallpaper.getDescription()); + } else { + connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false, + wpdData.mWidth, wpdData.mHeight, + wpdData.mPadding, mDisplayId, wallpaper.mWhich, connection.mInfo, + /* description= */ null); + } } catch (RemoteException e) { Slog.w(TAG, "Failed attaching wallpaper on display", e); if (wallpaper != null && !wallpaper.wallpaperUpdating && connection.getConnectedEngineSize() == 0) { wallpaper.mBindSource = BindSource.CONNECT_LOCKED; - bindWallpaperComponentLocked(null /* componentName */, false /* force */, - false /* fromUser */, wallpaper, null /* reply */); + bindWallpaperComponentLocked(null, false /* force */, false /* fromUser */, + wallpaper, null /* reply */); } } t.traceEnd(); @@ -1324,7 +1335,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (DEBUG) { Slog.v(TAG, "static system+lock to system success"); } - lockWp.setComponent(mOriginalSystem.getComponent()); + if (liveWallpaperContentHandling()) { + lockWp.setDescription(mOriginalSystem.getDescription()); + } else { + lockWp.setComponent(mOriginalSystem.getComponent()); + } lockWp.connection = mOriginalSystem.connection; lockWp.connection.mWallpaper = lockWp; mOriginalSystem.mWhich = FLAG_LOCK; @@ -1391,7 +1406,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub Slog.i(TAG, "Wallpaper " + wpService + " update has finished"); } wallpaper.wallpaperUpdating = false; - clearWallpaperComponentLocked(wallpaper); + detachWallpaperLocked(wallpaper); wallpaper.mBindSource = BindSource.PACKAGE_UPDATE_FINISHED; if (!bindWallpaperComponentLocked(wpService, false, false, wallpaper, null)) { @@ -1905,6 +1920,23 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false; if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false; + if (liveWallpaperContentHandling()) { + final WallpaperDescription description = wallpaper.getDescription(); + if (!bindWallpaperDescriptionLocked(description, true, false, wallpaper, reply)) { + // We failed to bind the desired wallpaper, but that might + // happen if the wallpaper isn't direct-boot aware + ServiceInfo si = null; + try { + si = mIPackageManager.getServiceInfo(description.getComponent(), + PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId); + } catch (RemoteException e) { + Slog.w(TAG, "Failure starting previous wallpaper; clearing", e); + } + onSwitchWallpaperFailLocked(wallpaper, reply, si); + } + return; + } + final ComponentName cname; if (removeNextWallpaperComponent()) { cname = wallpaper.getComponent(); @@ -2001,9 +2033,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub try { if (userId != mCurrentUserId && !hasCrossUserPermission()) return; - final ComponentName component; - final int finalWhich; - // Clear any previous ImageWallpaper related fields List<WallpaperData> toClear = new ArrayList<>(); if ((which & FLAG_LOCK) > 0 && lockWallpaper != null) toClear.add(lockWallpaper); @@ -2017,19 +2046,34 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - // lock only case: set the system wallpaper component to both screens - if (which == FLAG_LOCK) { - component = wallpaper.getComponent(); - finalWhich = FLAG_LOCK | FLAG_SYSTEM; + final WallpaperDescription description; + final int finalWhich; + + if (liveWallpaperContentHandling()) { + if (which == FLAG_LOCK) { + // lock only case: set the system wallpaper component to both screens + description = wallpaper.getDescription(); + finalWhich = FLAG_LOCK | FLAG_SYSTEM; + } else { + description = new WallpaperDescription.Builder().build(); + finalWhich = which; + } } else { - component = null; - finalWhich = which; + if (which == FLAG_LOCK) { + // lock only case: set the system wallpaper component to both screens + description = new WallpaperDescription.Builder().setComponent( + wallpaper.getComponent()).build(); + finalWhich = FLAG_LOCK | FLAG_SYSTEM; + } else { + description = new WallpaperDescription.Builder().build(); + finalWhich = which; + } } // except for the lock case (for which we keep the system wallpaper as-is), force rebind boolean force = which != FLAG_LOCK; - boolean success = withCleanCallingIdentity(() -> setWallpaperComponentInternal( - component, finalWhich, userId, force, fromForeground, reply)); + boolean success = withCleanCallingIdentity(() -> setWallpaperDescriptionInternal( + description, finalWhich, userId, force, fromForeground, reply)); if (success) return; } catch (IllegalArgumentException e1) { e = e1; @@ -2040,7 +2084,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // let's not let it crash the system and just live with no // wallpaper. Slog.e(TAG, "Default wallpaper component not found!", e); - withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper)); + withCleanCallingIdentity(() -> { + wallpaper.mBindSource = BindSource.FALLBACK_DEFAULT_MISSING; + bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper, reply); + }); if (reply != null) { try { reply.sendResult(null); @@ -2412,6 +2459,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub @Override public WallpaperInfo getWallpaperInfoWithFlags(@SetWallpaperFlags int which, int userId) { + if (liveWallpaperContentHandling()) { + return getWallpaperInstance(which, userId, false).getInfo(); + } userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null); @@ -2425,13 +2475,45 @@ public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperInfo info = wallpaper.connection.mInfo; if (hasPermission(READ_WALLPAPER_INTERNAL) || mPackageManagerInternal.canQueryPackage( - Binder.getCallingUid(), info.getComponent().getPackageName())) { + Binder.getCallingUid(), info.getComponent().getPackageName())) { return info; } } return null; } + @NonNull + @Override + public WallpaperInstance getWallpaperInstance(@SetWallpaperFlags int which, int userId) { + return getWallpaperInstance(which, userId, true); + } + + private WallpaperInstance getWallpaperInstance(@SetWallpaperFlags int which, int userId, + boolean requireReadWallpaper) { + final WallpaperInstance defaultInstance = new WallpaperInstance(null, + new WallpaperDescription.Builder().build()); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null); + synchronized (mLock) { + WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId) + : mWallpaperMap.get(userId); + if (wallpaper == null + || wallpaper.connection == null + || wallpaper.connection.mInfo == null) { + return defaultInstance; + } + + WallpaperInfo info = wallpaper.connection.mInfo; + boolean canQueryPackage = mPackageManagerInternal.canQueryPackage( + Binder.getCallingUid(), info.getComponent().getPackageName()); + if (hasPermission(READ_WALLPAPER_INTERNAL) + || (canQueryPackage && !requireReadWallpaper)) { + return new WallpaperInstance(info, wallpaper.getDescription()); + } + } + return defaultInstance; + } + @Override public ParcelFileDescriptor getWallpaperInfoFile(int userId) { synchronized (mLock) { @@ -3159,11 +3241,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } @Override - public void setWallpaperComponentChecked(ComponentName name, String callingPackage, - @SetWallpaperFlags int which, int userId) { + public void setWallpaperComponentChecked(WallpaperDescription description, + String callingPackage, @SetWallpaperFlags int which, int userId) { if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) { - setWallpaperComponent(name, callingPackage, which, userId); + setWallpaperDescription(description, callingPackage, which, userId); } } @@ -3176,12 +3258,23 @@ public class WallpaperManagerService extends IWallpaperManager.Stub @VisibleForTesting boolean setWallpaperComponent(ComponentName name, String callingPackage, @SetWallpaperFlags int which, int userId) { + return setWallpaperDescription( + new WallpaperDescription.Builder().setComponent(name).build(), callingPackage, + which, userId); + } + + @VisibleForTesting + boolean setWallpaperDescription(WallpaperDescription description, String callingPackage, + @SetWallpaperFlags int which, int userId) { boolean fromForeground = isFromForegroundApp(callingPackage); - return setWallpaperComponentInternal(name, which, userId, false, fromForeground, null); + return setWallpaperDescriptionInternal(description, which, userId, false, fromForeground, + null); } - private boolean setWallpaperComponentInternal(ComponentName name, @SetWallpaperFlags int which, - int userIdIn, boolean force, boolean fromForeground, IRemoteCallback reply) { + private boolean setWallpaperDescriptionInternal(@NonNull WallpaperDescription description, + @SetWallpaperFlags int which, int userIdIn, boolean force, boolean fromForeground, + IRemoteCallback reply) { + ComponentName name = description.getComponent(); if (DEBUG) { Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name); } @@ -3191,11 +3284,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); boolean shouldNotifyColors = false; + final boolean bindSuccess; // If the lockscreen wallpaper is set to the same as the home screen, notify that the // lockscreen wallpaper colors changed, even if we don't bind a new wallpaper engine. boolean shouldNotifyLockscreenColors = false; - boolean bindSuccess; final WallpaperData newWallpaper; synchronized (mLock) { @@ -3226,8 +3319,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub final WallpaperDestinationChangeHandler liveSync = new WallpaperDestinationChangeHandler( newWallpaper); - boolean same = changingToSame(name, newWallpaper.connection, - newWallpaper.getComponent()); + boolean same; + if (liveWallpaperContentHandling()) { + same = changingToSame(description, newWallpaper.connection, + newWallpaper.getDescription()); + } else { + same = changingToSame(name, newWallpaper.connection, + newWallpaper.getComponent()); + } /* * If we have a shared system+lock wallpaper, and we reapply the same wallpaper @@ -3238,8 +3337,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub newWallpaper.mBindSource = (name == null) ? BindSource.SET_LIVE_TO_CLEAR : BindSource.SET_LIVE; - bindSuccess = bindWallpaperComponentLocked(name, /* force */ - forceRebind, /* fromUser */ true, newWallpaper, reply); + if (liveWallpaperContentHandling()) { + bindSuccess = bindWallpaperDescriptionLocked(description, forceRebind, + /* fromUser */ true, newWallpaper, reply); + } else { + bindSuccess = bindWallpaperComponentLocked(name, forceRebind, + /* fromUser */ true, newWallpaper, reply); + } if (bindSuccess) { if (!same || (offloadColorExtraction() && forceRebind)) { newWallpaper.primaryColors = null; @@ -3335,6 +3439,24 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return false; } + private boolean changingToSame(WallpaperDescription newDescription, + WallpaperConnection currentConnection, WallpaperDescription currentDescription) { + if (currentConnection == null) { + return false; + } + if (isDefaultComponent(newDescription.getComponent()) && isDefaultComponent( + currentDescription.getComponent())) { + if (DEBUG) Slog.v(TAG, "changingToSame: still using default"); + // Still using default wallpaper. + return true; + } else if (newDescription.equals(currentDescription)) { + // Changing to same wallpaper. + if (DEBUG) Slog.v(TAG, "same wallpaper"); + return true; + } + return false; + } + /* * Attempt to bind the wallpaper given by `componentName`, returning true on success otherwise * false. @@ -3352,12 +3474,29 @@ public class WallpaperManagerService extends IWallpaperManager.Stub */ boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) { + return bindWallpaperDescriptionLocked( + new WallpaperDescription.Builder().setComponent(componentName).build(), force, + fromUser, wallpaper, reply); + } + + // When `liveWallpaperContentHandling()` is false this acts exactly like the version which takes + // a ComponentName argument did: it uses the ComponentName from `description`, it binds the + // service given by that component, and updates WallpaperData with that component on success. + boolean bindWallpaperDescriptionLocked(WallpaperDescription description, boolean force, + boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) { + ComponentName componentName = description.getComponent(); if (DEBUG_LIVE) { Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName); } - // Has the component changed? - if (!force && changingToSame(componentName, wallpaper.connection, - wallpaper.getComponent())) { + boolean skipBinding; + if (liveWallpaperContentHandling()) { + skipBinding = !force && changingToSame(description, wallpaper.connection, + wallpaper.getDescription()); + } else { + skipBinding = !force && changingToSame(componentName, wallpaper.connection, + wallpaper.getComponent()); + } + if (skipBinding) { try { if (DEBUG_LIVE) { Slog.v(TAG, "Changing to the same component, ignoring"); @@ -3374,6 +3513,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub try { if (componentName == null) { componentName = mDefaultWallpaperComponent; + if (liveWallpaperContentHandling()) { + description = description.toBuilder().setComponent(componentName).build(); + } } int serviceUserId = wallpaper.userId; ServiceInfo si = mIPackageManager.getServiceInfo(componentName, @@ -3494,7 +3636,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return false; } maybeDetachLastWallpapers(wallpaper); - wallpaper.setComponent(componentName); + if (liveWallpaperContentHandling()) { + wallpaper.setDescription(description); + } else { + wallpaper.setComponent(componentName); + } wallpaper.connection = newConn; newConn.mReply = reply; updateCurrentWallpapers(wallpaper); @@ -3618,11 +3764,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub }); } - private void clearWallpaperComponentLocked(WallpaperData wallpaper) { - wallpaper.setComponent(null); - detachWallpaperLocked(wallpaper); - } - private void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) { TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); t.traceBegin("WPMS.attachServiceLocked"); @@ -3858,6 +3999,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } // Called by SystemBackupAgent after files are restored to disk. + // TODO(b/373875373) Remove this method public void settingsRestored() { // Verify caller is the system if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { @@ -3876,6 +4018,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub ComponentName componentName = removeNextWallpaperComponent() ? wallpaper.getComponent() : wallpaper.nextWallpaperComponent; + + if (liveWallpaperContentHandling()) { + // Per b/373875373 this method should be removed, so we just set wallpapers to + // default. + bindWallpaperDescriptionLocked(new WallpaperDescription.Builder().build(), false, + false, wallpaper, null); + return; + } if (componentName != null && !componentName.equals(mImageWallpaper)) { wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_LIVE_SUCCESS; if (!bindWallpaperComponentLocked(componentName, false, false, @@ -3894,15 +4044,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty"); success = true; } else { - if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource"); + if (DEBUG) { + Slog.v(TAG, "settingsRestored: attempting to restore named resource"); + } success = mWallpaperDataParser.restoreNamedResourceLocked(wallpaper); } - if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success - + " id=" + wallpaper.wallpaperId); + if (DEBUG) { + Slog.v(TAG, "settingsRestored: success=" + success + " id=" + + wallpaper.wallpaperId); + } if (success) { - mWallpaperCropper.generateCrop(wallpaper); // based on the new image + metadata + mWallpaperCropper.generateCrop( + wallpaper); // based on the new image + metadata wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_STATIC; - bindWallpaperComponentLocked(componentName, true, false, wallpaper, null); + bindWallpaperComponentLocked(null, true, false, wallpaper, null); } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java index 1ea36748eb5d..db323f1b68e7 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java @@ -46,6 +46,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; @@ -535,7 +536,8 @@ public class WallpaperManagerServiceTests { doReturn(wallpaper).when(mService).getWallpaperSafeLocked(wallpaper.userId, FLAG_SYSTEM); doNothing().when(mService).switchWallpaper(any(), any()); doReturn(true).when(mService) - .bindWallpaperComponentLocked(any(), anyBoolean(), anyBoolean(), any(), any()); + .bindWallpaperComponentLocked(isA(ComponentName.class), anyBoolean(), anyBoolean(), + any(), any()); doNothing().when(mService).saveSettingsLocked(wallpaper.userId); spyOn(mService.mWallpaperCropper); doNothing().when(mService.mWallpaperCropper).generateCrop(wallpaper); |