Loading services/core/java/com/android/server/wallpaper/WallpaperData.java +2 −2 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import android.app.WallpaperManager.SetWallpaperFlags; import android.content.ComponentName; import android.graphics.Rect; import android.os.RemoteCallbackList; import android.util.ArrayMap; import android.util.SparseArray; import java.io.File; Loading Loading @@ -115,7 +115,7 @@ class WallpaperData { * A map to keep track of the dimming set by different applications. The key is the calling * UID and the value is the dim amount. */ ArrayMap<Integer, Float> mUidToDimAmount = new ArrayMap<>(); SparseArray<Float> mUidToDimAmount = new SparseArray<>(); /** * Whether we need to extract the wallpaper colors again to calculate the dark hints Loading services/core/java/com/android/server/wallpaper/WallpaperDataParser.java 0 → 100644 +550 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wallpaper; import static android.app.WallpaperManager.FLAG_LOCK; import static android.app.WallpaperManager.FLAG_SYSTEM; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.wallpaper.WallpaperDisplayHelper.DisplayData; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_INFO; import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir; import static com.android.server.wallpaper.WallpaperUtils.makeWallpaperIdLocked; import android.annotation.Nullable; import android.app.WallpaperColors; import android.app.backup.WallpaperBackupHelper; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Color; import android.os.FileUtils; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.JournaledFile; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; /** * Helper for the wallpaper loading / saving / xml parsing * Only meant to be used lock held by WallpaperManagerService * Only meant to be instantiated once by WallpaperManagerService */ class WallpaperDataParser { private static final String TAG = WallpaperDataParser.class.getSimpleName(); private static final boolean DEBUG = false; private final ComponentName mImageWallpaper; private final WallpaperDisplayHelper mWallpaperDisplayHelper; private final WallpaperCropper mWallpaperCropper; private final Context mContext; WallpaperDataParser(Context context, WallpaperDisplayHelper wallpaperDisplayHelper, WallpaperCropper wallpaperCropper) { mContext = context; mWallpaperDisplayHelper = wallpaperDisplayHelper; mWallpaperCropper = wallpaperCropper; mImageWallpaper = ComponentName.unflattenFromString( context.getResources().getString(R.string.image_wallpaper_component)); } private JournaledFile makeJournaledFile(int userId) { final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); } static class WallpaperLoadingResult { private final WallpaperData mSystemWallpaperData; @Nullable private final WallpaperData mLockWallpaperData; private final boolean mSuccess; private WallpaperLoadingResult( WallpaperData systemWallpaperData, WallpaperData lockWallpaperData, boolean success) { mSystemWallpaperData = systemWallpaperData; mLockWallpaperData = lockWallpaperData; mSuccess = success; } public WallpaperData getSystemWallpaperData() { return mSystemWallpaperData; } public WallpaperData getLockWallpaperData() { return mLockWallpaperData; } public boolean success() { return mSuccess; } } /** * Load the system wallpaper (and the lock wallpaper, if it exists) from disk * @param userId the id of the user for which the wallpaper should be loaded * @param keepDimensionHints if false, parse and set the * {@link DisplayData} width and height for the specified userId * @param wallpaper the wallpaper object to reuse to do the modifications. * If null, a new object will be created. * @param lockWallpaper the lock wallpaper object to reuse to do the modifications. * If null, a new object will be created. * @return a {@link WallpaperLoadingResult} object containing the wallpaper data. * This object will contain the {@code wallpaper} and * {@code lockWallpaper} provided as parameters, if they are not null. */ public WallpaperLoadingResult loadSettingsLocked(int userId, boolean keepDimensionHints, WallpaperData wallpaper, WallpaperData lockWallpaper) { JournaledFile journal = makeJournaledFile(userId); FileInputStream stream = null; File file = journal.chooseForRead(); if (wallpaper == null) { // Do this once per boot migrateFromOld(); wallpaper = new WallpaperData(userId, FLAG_SYSTEM); wallpaper.allowBackup = true; if (!wallpaper.cropExists()) { if (wallpaper.sourceExists()) { mWallpaperCropper.generateCrop(wallpaper); } else { Slog.i(TAG, "No static wallpaper imagery; defaults will be shown"); } } } final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); boolean success = false; try { stream = new FileInputStream(file); TypedXmlPullParser parser = Xml.resolvePullParser(stream); int type; do { type = parser.next(); if (type == XmlPullParser.START_TAG) { String tag = parser.getName(); if ("wp".equals(tag)) { // Common to system + lock wallpapers parseWallpaperAttributes(parser, wallpaper, keepDimensionHints); // A system wallpaper might also be a live wallpaper String comp = parser.getAttributeValue(null, "component"); wallpaper.nextWallpaperComponent = comp != null ? ComponentName.unflattenFromString(comp) : null; if (wallpaper.nextWallpaperComponent == null || "android".equals(wallpaper.nextWallpaperComponent .getPackageName())) { wallpaper.nextWallpaperComponent = mImageWallpaper; } if (DEBUG) { Slog.v(TAG, "mWidth:" + wpdData.mWidth); Slog.v(TAG, "mHeight:" + wpdData.mHeight); Slog.v(TAG, "cropRect:" + wallpaper.cropHint); Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors); Slog.v(TAG, "mName:" + wallpaper.name); Slog.v(TAG, "mNextWallpaperComponent:" + wallpaper.nextWallpaperComponent); } } else if ("kwp".equals(tag)) { // keyguard-specific wallpaper for this user if (lockWallpaper == null) { lockWallpaper = new WallpaperData(userId, FLAG_LOCK); } parseWallpaperAttributes(parser, lockWallpaper, false); } } } while (type != XmlPullParser.END_DOCUMENT); 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) { Slog.w(TAG, "failed parsing " + file + " " + e); } IoUtils.closeQuietly(stream); if (!success) { wallpaper.cropHint.set(0, 0, 0, 0); wpdData.mPadding.set(0, 0, 0, 0); wallpaper.name = ""; lockWallpaper = null; } else { if (wallpaper.wallpaperId <= 0) { wallpaper.wallpaperId = makeWallpaperIdLocked(); if (DEBUG) { Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId + "); now " + wallpaper.wallpaperId); } } } mWallpaperDisplayHelper.ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY); ensureSaneWallpaperData(wallpaper); if (lockWallpaper != null) { ensureSaneWallpaperData(lockWallpaper); lockWallpaper.mWhich = FLAG_LOCK; wallpaper.mWhich = FLAG_SYSTEM; } else { wallpaper.mWhich = FLAG_SYSTEM | FLAG_LOCK; } return new WallpaperLoadingResult(wallpaper, lockWallpaper, success); } private void ensureSaneWallpaperData(WallpaperData wallpaper) { // Only overwrite cropHint if the rectangle is invalid. if (wallpaper.cropHint.width() < 0 || wallpaper.cropHint.height() < 0) { wallpaper.cropHint.set(0, 0, 0, 0); } } private void migrateFromOld() { // Pre-N, what existed is the one we're now using as the display crop File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP); // In the very-long-ago, imagery lived with the settings app File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY); File newWallpaper = new File(getWallpaperDir(0), WALLPAPER); // Migrations from earlier wallpaper image storage schemas if (preNWallpaper.exists()) { if (!newWallpaper.exists()) { // we've got the 'wallpaper' crop file but not the nominal source image, // so do the simple "just take everything" straight copy of legacy data if (DEBUG) { Slog.i(TAG, "Migrating wallpaper schema"); } FileUtils.copyFile(preNWallpaper, newWallpaper); } // else we're in the usual modern case: both source & crop exist } else if (originalWallpaper.exists()) { // VERY old schema; make sure things exist and are in the right place if (DEBUG) { Slog.i(TAG, "Migrating antique wallpaper schema"); } File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY); if (oldInfo.exists()) { File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO); oldInfo.renameTo(newInfo); } FileUtils.copyFile(originalWallpaper, preNWallpaper); originalWallpaper.renameTo(newWallpaper); } } @VisibleForTesting void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper, boolean keepDimensionHints) throws XmlPullParserException { final int id = parser.getAttributeInt(null, "id", -1); if (id != -1) { wallpaper.wallpaperId = id; if (id > WallpaperUtils.getCurrentWallpaperId()) { WallpaperUtils.setCurrentWallpaperId(id); } } else { wallpaper.wallpaperId = makeWallpaperIdLocked(); } final DisplayData wpData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); if (!keepDimensionHints) { wpData.mWidth = parser.getAttributeInt(null, "width"); wpData.mHeight = parser.getAttributeInt(null, "height"); } wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0); wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0); wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0); wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); wpData.mPadding.left = getAttributeInt(parser, "paddingLeft", 0); wpData.mPadding.top = getAttributeInt(parser, "paddingTop", 0); wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0); wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0); wallpaper.mWallpaperDimAmount = getAttributeFloat(parser, "dimAmount", 0f); int dimAmountsCount = getAttributeInt(parser, "dimAmountsCount", 0); if (dimAmountsCount > 0) { SparseArray<Float> allDimAmounts = new SparseArray<>(dimAmountsCount); for (int i = 0; i < dimAmountsCount; i++) { int uid = getAttributeInt(parser, "dimUID" + i, 0); float dimValue = getAttributeFloat(parser, "dimValue" + i, 0f); allDimAmounts.put(uid, dimValue); } wallpaper.mUidToDimAmount = allDimAmounts; } int colorsCount = getAttributeInt(parser, "colorsCount", 0); int allColorsCount = getAttributeInt(parser, "allColorsCount", 0); if (allColorsCount > 0) { Map<Integer, Integer> allColors = new HashMap<>(allColorsCount); for (int i = 0; i < allColorsCount; i++) { int colorInt = getAttributeInt(parser, "allColorsValue" + i, 0); int population = getAttributeInt(parser, "allColorsPopulation" + i, 0); allColors.put(colorInt, population); } int colorHints = getAttributeInt(parser, "colorHints", 0); wallpaper.primaryColors = new WallpaperColors(allColors, colorHints); } else if (colorsCount > 0) { Color primary = null, secondary = null, tertiary = null; for (int i = 0; i < colorsCount; i++) { Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0)); if (i == 0) { primary = color; } else if (i == 1) { secondary = color; } else if (i == 2) { tertiary = color; } else { break; } } int colorHints = getAttributeInt(parser, "colorHints", 0); wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints); } wallpaper.name = parser.getAttributeValue(null, "name"); wallpaper.allowBackup = parser.getAttributeBoolean(null, "backup", false); } private int getAttributeInt(TypedXmlPullParser parser, String name, int defValue) { return parser.getAttributeInt(null, name, defValue); } private float getAttributeFloat(TypedXmlPullParser parser, String name, float defValue) { return parser.getAttributeFloat(null, name, defValue); } void saveSettingsLocked(int userId, WallpaperData wallpaper, WallpaperData lockWallpaper) { JournaledFile journal = makeJournaledFile(userId); FileOutputStream fstream = null; try { fstream = new FileOutputStream(journal.chooseForWrite(), false); TypedXmlSerializer out = Xml.resolveSerializer(fstream); out.startDocument(null, true); if (wallpaper != null) { writeWallpaperAttributes(out, "wp", wallpaper); } if (lockWallpaper != null) { writeWallpaperAttributes(out, "kwp", lockWallpaper); } out.endDocument(); fstream.flush(); FileUtils.sync(fstream); fstream.close(); journal.commit(); } catch (IOException e) { IoUtils.closeQuietly(fstream); journal.rollback(); } } @VisibleForTesting void writeWallpaperAttributes(TypedXmlSerializer out, String tag, WallpaperData wallpaper) throws IllegalArgumentException, IllegalStateException, IOException { if (DEBUG) { Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId); } final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); out.startTag(null, tag); out.attributeInt(null, "id", wallpaper.wallpaperId); out.attributeInt(null, "width", wpdData.mWidth); out.attributeInt(null, "height", wpdData.mHeight); out.attributeInt(null, "cropLeft", wallpaper.cropHint.left); out.attributeInt(null, "cropTop", wallpaper.cropHint.top); out.attributeInt(null, "cropRight", wallpaper.cropHint.right); out.attributeInt(null, "cropBottom", wallpaper.cropHint.bottom); if (wpdData.mPadding.left != 0) { out.attributeInt(null, "paddingLeft", wpdData.mPadding.left); } if (wpdData.mPadding.top != 0) { out.attributeInt(null, "paddingTop", wpdData.mPadding.top); } if (wpdData.mPadding.right != 0) { out.attributeInt(null, "paddingRight", wpdData.mPadding.right); } if (wpdData.mPadding.bottom != 0) { out.attributeInt(null, "paddingBottom", wpdData.mPadding.bottom); } out.attributeFloat(null, "dimAmount", wallpaper.mWallpaperDimAmount); int dimAmountsCount = wallpaper.mUidToDimAmount.size(); out.attributeInt(null, "dimAmountsCount", dimAmountsCount); if (dimAmountsCount > 0) { int index = 0; for (int i = 0; i < wallpaper.mUidToDimAmount.size(); i++) { out.attributeInt(null, "dimUID" + index, wallpaper.mUidToDimAmount.keyAt(i)); out.attributeFloat(null, "dimValue" + index, wallpaper.mUidToDimAmount.valueAt(i)); index++; } } if (wallpaper.primaryColors != null) { int colorsCount = wallpaper.primaryColors.getMainColors().size(); out.attributeInt(null, "colorsCount", colorsCount); if (colorsCount > 0) { for (int i = 0; i < colorsCount; i++) { final Color wc = wallpaper.primaryColors.getMainColors().get(i); out.attributeInt(null, "colorValue" + i, wc.toArgb()); } } int allColorsCount = wallpaper.primaryColors.getAllColors().size(); out.attributeInt(null, "allColorsCount", allColorsCount); if (allColorsCount > 0) { int index = 0; for (Map.Entry<Integer, Integer> entry : wallpaper.primaryColors.getAllColors() .entrySet()) { out.attributeInt(null, "allColorsValue" + index, entry.getKey()); out.attributeInt(null, "allColorsPopulation" + index, entry.getValue()); index++; } } out.attributeInt(null, "colorHints", wallpaper.primaryColors.getColorHints()); } out.attribute(null, "name", wallpaper.name); if (wallpaper.wallpaperComponent != null && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) { out.attribute(null, "component", wallpaper.wallpaperComponent.flattenToShortString()); } if (wallpaper.allowBackup) { out.attributeBoolean(null, "backup", true); } out.endTag(null, tag); } // Restore the named resource bitmap to both source + crop files boolean restoreNamedResourceLocked(WallpaperData wallpaper) { if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) { String resName = wallpaper.name.substring(4); String pkg = null; int colon = resName.indexOf(':'); if (colon > 0) { pkg = resName.substring(0, colon); } String ident = null; int slash = resName.lastIndexOf('/'); if (slash > 0) { ident = resName.substring(slash + 1); } String type = null; if (colon > 0 && slash > 0 && (slash - colon) > 1) { type = resName.substring(colon + 1, slash); } if (pkg != null && ident != null && type != null) { int resId = -1; InputStream res = null; FileOutputStream fos = null; FileOutputStream cos = null; try { Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED); Resources r = c.getResources(); resId = r.getIdentifier(resName, null, null); if (resId == 0) { Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type + " ident=" + ident); return false; } res = r.openRawResource(resId); if (wallpaper.wallpaperFile.exists()) { wallpaper.wallpaperFile.delete(); wallpaper.cropFile.delete(); } fos = new FileOutputStream(wallpaper.wallpaperFile); cos = new FileOutputStream(wallpaper.cropFile); byte[] buffer = new byte[32768]; int amt; while ((amt = res.read(buffer)) > 0) { fos.write(buffer, 0, amt); cos.write(buffer, 0, amt); } // mWallpaperObserver will notice the close and send the change broadcast Slog.v(TAG, "Restored wallpaper: " + resName); return true; } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Package name " + pkg + " not found"); } catch (Resources.NotFoundException e) { Slog.e(TAG, "Resource not found: " + resId); } catch (IOException e) { Slog.e(TAG, "IOException while restoring wallpaper ", e); } finally { IoUtils.closeQuietly(res); if (fos != null) { FileUtils.sync(fos); } if (cos != null) { FileUtils.sync(cos); } IoUtils.closeQuietly(fos); IoUtils.closeQuietly(cos); } } } return false; } } services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.view.DisplayInfo; import com.android.server.wm.WindowManagerInternal; import java.util.function.Consumer; /** * Internal class used to store all the display data relevant to the wallpapers */ Loading Loading
services/core/java/com/android/server/wallpaper/WallpaperData.java +2 −2 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import android.app.WallpaperManager.SetWallpaperFlags; import android.content.ComponentName; import android.graphics.Rect; import android.os.RemoteCallbackList; import android.util.ArrayMap; import android.util.SparseArray; import java.io.File; Loading Loading @@ -115,7 +115,7 @@ class WallpaperData { * A map to keep track of the dimming set by different applications. The key is the calling * UID and the value is the dim amount. */ ArrayMap<Integer, Float> mUidToDimAmount = new ArrayMap<>(); SparseArray<Float> mUidToDimAmount = new SparseArray<>(); /** * Whether we need to extract the wallpaper colors again to calculate the dark hints Loading
services/core/java/com/android/server/wallpaper/WallpaperDataParser.java 0 → 100644 +550 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wallpaper; import static android.app.WallpaperManager.FLAG_LOCK; import static android.app.WallpaperManager.FLAG_SYSTEM; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.wallpaper.WallpaperDisplayHelper.DisplayData; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_INFO; import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir; import static com.android.server.wallpaper.WallpaperUtils.makeWallpaperIdLocked; import android.annotation.Nullable; import android.app.WallpaperColors; import android.app.backup.WallpaperBackupHelper; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Color; import android.os.FileUtils; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.JournaledFile; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; /** * Helper for the wallpaper loading / saving / xml parsing * Only meant to be used lock held by WallpaperManagerService * Only meant to be instantiated once by WallpaperManagerService */ class WallpaperDataParser { private static final String TAG = WallpaperDataParser.class.getSimpleName(); private static final boolean DEBUG = false; private final ComponentName mImageWallpaper; private final WallpaperDisplayHelper mWallpaperDisplayHelper; private final WallpaperCropper mWallpaperCropper; private final Context mContext; WallpaperDataParser(Context context, WallpaperDisplayHelper wallpaperDisplayHelper, WallpaperCropper wallpaperCropper) { mContext = context; mWallpaperDisplayHelper = wallpaperDisplayHelper; mWallpaperCropper = wallpaperCropper; mImageWallpaper = ComponentName.unflattenFromString( context.getResources().getString(R.string.image_wallpaper_component)); } private JournaledFile makeJournaledFile(int userId) { final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); } static class WallpaperLoadingResult { private final WallpaperData mSystemWallpaperData; @Nullable private final WallpaperData mLockWallpaperData; private final boolean mSuccess; private WallpaperLoadingResult( WallpaperData systemWallpaperData, WallpaperData lockWallpaperData, boolean success) { mSystemWallpaperData = systemWallpaperData; mLockWallpaperData = lockWallpaperData; mSuccess = success; } public WallpaperData getSystemWallpaperData() { return mSystemWallpaperData; } public WallpaperData getLockWallpaperData() { return mLockWallpaperData; } public boolean success() { return mSuccess; } } /** * Load the system wallpaper (and the lock wallpaper, if it exists) from disk * @param userId the id of the user for which the wallpaper should be loaded * @param keepDimensionHints if false, parse and set the * {@link DisplayData} width and height for the specified userId * @param wallpaper the wallpaper object to reuse to do the modifications. * If null, a new object will be created. * @param lockWallpaper the lock wallpaper object to reuse to do the modifications. * If null, a new object will be created. * @return a {@link WallpaperLoadingResult} object containing the wallpaper data. * This object will contain the {@code wallpaper} and * {@code lockWallpaper} provided as parameters, if they are not null. */ public WallpaperLoadingResult loadSettingsLocked(int userId, boolean keepDimensionHints, WallpaperData wallpaper, WallpaperData lockWallpaper) { JournaledFile journal = makeJournaledFile(userId); FileInputStream stream = null; File file = journal.chooseForRead(); if (wallpaper == null) { // Do this once per boot migrateFromOld(); wallpaper = new WallpaperData(userId, FLAG_SYSTEM); wallpaper.allowBackup = true; if (!wallpaper.cropExists()) { if (wallpaper.sourceExists()) { mWallpaperCropper.generateCrop(wallpaper); } else { Slog.i(TAG, "No static wallpaper imagery; defaults will be shown"); } } } final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); boolean success = false; try { stream = new FileInputStream(file); TypedXmlPullParser parser = Xml.resolvePullParser(stream); int type; do { type = parser.next(); if (type == XmlPullParser.START_TAG) { String tag = parser.getName(); if ("wp".equals(tag)) { // Common to system + lock wallpapers parseWallpaperAttributes(parser, wallpaper, keepDimensionHints); // A system wallpaper might also be a live wallpaper String comp = parser.getAttributeValue(null, "component"); wallpaper.nextWallpaperComponent = comp != null ? ComponentName.unflattenFromString(comp) : null; if (wallpaper.nextWallpaperComponent == null || "android".equals(wallpaper.nextWallpaperComponent .getPackageName())) { wallpaper.nextWallpaperComponent = mImageWallpaper; } if (DEBUG) { Slog.v(TAG, "mWidth:" + wpdData.mWidth); Slog.v(TAG, "mHeight:" + wpdData.mHeight); Slog.v(TAG, "cropRect:" + wallpaper.cropHint); Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors); Slog.v(TAG, "mName:" + wallpaper.name); Slog.v(TAG, "mNextWallpaperComponent:" + wallpaper.nextWallpaperComponent); } } else if ("kwp".equals(tag)) { // keyguard-specific wallpaper for this user if (lockWallpaper == null) { lockWallpaper = new WallpaperData(userId, FLAG_LOCK); } parseWallpaperAttributes(parser, lockWallpaper, false); } } } while (type != XmlPullParser.END_DOCUMENT); 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) { Slog.w(TAG, "failed parsing " + file + " " + e); } IoUtils.closeQuietly(stream); if (!success) { wallpaper.cropHint.set(0, 0, 0, 0); wpdData.mPadding.set(0, 0, 0, 0); wallpaper.name = ""; lockWallpaper = null; } else { if (wallpaper.wallpaperId <= 0) { wallpaper.wallpaperId = makeWallpaperIdLocked(); if (DEBUG) { Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId + "); now " + wallpaper.wallpaperId); } } } mWallpaperDisplayHelper.ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY); ensureSaneWallpaperData(wallpaper); if (lockWallpaper != null) { ensureSaneWallpaperData(lockWallpaper); lockWallpaper.mWhich = FLAG_LOCK; wallpaper.mWhich = FLAG_SYSTEM; } else { wallpaper.mWhich = FLAG_SYSTEM | FLAG_LOCK; } return new WallpaperLoadingResult(wallpaper, lockWallpaper, success); } private void ensureSaneWallpaperData(WallpaperData wallpaper) { // Only overwrite cropHint if the rectangle is invalid. if (wallpaper.cropHint.width() < 0 || wallpaper.cropHint.height() < 0) { wallpaper.cropHint.set(0, 0, 0, 0); } } private void migrateFromOld() { // Pre-N, what existed is the one we're now using as the display crop File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP); // In the very-long-ago, imagery lived with the settings app File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY); File newWallpaper = new File(getWallpaperDir(0), WALLPAPER); // Migrations from earlier wallpaper image storage schemas if (preNWallpaper.exists()) { if (!newWallpaper.exists()) { // we've got the 'wallpaper' crop file but not the nominal source image, // so do the simple "just take everything" straight copy of legacy data if (DEBUG) { Slog.i(TAG, "Migrating wallpaper schema"); } FileUtils.copyFile(preNWallpaper, newWallpaper); } // else we're in the usual modern case: both source & crop exist } else if (originalWallpaper.exists()) { // VERY old schema; make sure things exist and are in the right place if (DEBUG) { Slog.i(TAG, "Migrating antique wallpaper schema"); } File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY); if (oldInfo.exists()) { File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO); oldInfo.renameTo(newInfo); } FileUtils.copyFile(originalWallpaper, preNWallpaper); originalWallpaper.renameTo(newWallpaper); } } @VisibleForTesting void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper, boolean keepDimensionHints) throws XmlPullParserException { final int id = parser.getAttributeInt(null, "id", -1); if (id != -1) { wallpaper.wallpaperId = id; if (id > WallpaperUtils.getCurrentWallpaperId()) { WallpaperUtils.setCurrentWallpaperId(id); } } else { wallpaper.wallpaperId = makeWallpaperIdLocked(); } final DisplayData wpData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); if (!keepDimensionHints) { wpData.mWidth = parser.getAttributeInt(null, "width"); wpData.mHeight = parser.getAttributeInt(null, "height"); } wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0); wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0); wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0); wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); wpData.mPadding.left = getAttributeInt(parser, "paddingLeft", 0); wpData.mPadding.top = getAttributeInt(parser, "paddingTop", 0); wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0); wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0); wallpaper.mWallpaperDimAmount = getAttributeFloat(parser, "dimAmount", 0f); int dimAmountsCount = getAttributeInt(parser, "dimAmountsCount", 0); if (dimAmountsCount > 0) { SparseArray<Float> allDimAmounts = new SparseArray<>(dimAmountsCount); for (int i = 0; i < dimAmountsCount; i++) { int uid = getAttributeInt(parser, "dimUID" + i, 0); float dimValue = getAttributeFloat(parser, "dimValue" + i, 0f); allDimAmounts.put(uid, dimValue); } wallpaper.mUidToDimAmount = allDimAmounts; } int colorsCount = getAttributeInt(parser, "colorsCount", 0); int allColorsCount = getAttributeInt(parser, "allColorsCount", 0); if (allColorsCount > 0) { Map<Integer, Integer> allColors = new HashMap<>(allColorsCount); for (int i = 0; i < allColorsCount; i++) { int colorInt = getAttributeInt(parser, "allColorsValue" + i, 0); int population = getAttributeInt(parser, "allColorsPopulation" + i, 0); allColors.put(colorInt, population); } int colorHints = getAttributeInt(parser, "colorHints", 0); wallpaper.primaryColors = new WallpaperColors(allColors, colorHints); } else if (colorsCount > 0) { Color primary = null, secondary = null, tertiary = null; for (int i = 0; i < colorsCount; i++) { Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0)); if (i == 0) { primary = color; } else if (i == 1) { secondary = color; } else if (i == 2) { tertiary = color; } else { break; } } int colorHints = getAttributeInt(parser, "colorHints", 0); wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints); } wallpaper.name = parser.getAttributeValue(null, "name"); wallpaper.allowBackup = parser.getAttributeBoolean(null, "backup", false); } private int getAttributeInt(TypedXmlPullParser parser, String name, int defValue) { return parser.getAttributeInt(null, name, defValue); } private float getAttributeFloat(TypedXmlPullParser parser, String name, float defValue) { return parser.getAttributeFloat(null, name, defValue); } void saveSettingsLocked(int userId, WallpaperData wallpaper, WallpaperData lockWallpaper) { JournaledFile journal = makeJournaledFile(userId); FileOutputStream fstream = null; try { fstream = new FileOutputStream(journal.chooseForWrite(), false); TypedXmlSerializer out = Xml.resolveSerializer(fstream); out.startDocument(null, true); if (wallpaper != null) { writeWallpaperAttributes(out, "wp", wallpaper); } if (lockWallpaper != null) { writeWallpaperAttributes(out, "kwp", lockWallpaper); } out.endDocument(); fstream.flush(); FileUtils.sync(fstream); fstream.close(); journal.commit(); } catch (IOException e) { IoUtils.closeQuietly(fstream); journal.rollback(); } } @VisibleForTesting void writeWallpaperAttributes(TypedXmlSerializer out, String tag, WallpaperData wallpaper) throws IllegalArgumentException, IllegalStateException, IOException { if (DEBUG) { Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId); } final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); out.startTag(null, tag); out.attributeInt(null, "id", wallpaper.wallpaperId); out.attributeInt(null, "width", wpdData.mWidth); out.attributeInt(null, "height", wpdData.mHeight); out.attributeInt(null, "cropLeft", wallpaper.cropHint.left); out.attributeInt(null, "cropTop", wallpaper.cropHint.top); out.attributeInt(null, "cropRight", wallpaper.cropHint.right); out.attributeInt(null, "cropBottom", wallpaper.cropHint.bottom); if (wpdData.mPadding.left != 0) { out.attributeInt(null, "paddingLeft", wpdData.mPadding.left); } if (wpdData.mPadding.top != 0) { out.attributeInt(null, "paddingTop", wpdData.mPadding.top); } if (wpdData.mPadding.right != 0) { out.attributeInt(null, "paddingRight", wpdData.mPadding.right); } if (wpdData.mPadding.bottom != 0) { out.attributeInt(null, "paddingBottom", wpdData.mPadding.bottom); } out.attributeFloat(null, "dimAmount", wallpaper.mWallpaperDimAmount); int dimAmountsCount = wallpaper.mUidToDimAmount.size(); out.attributeInt(null, "dimAmountsCount", dimAmountsCount); if (dimAmountsCount > 0) { int index = 0; for (int i = 0; i < wallpaper.mUidToDimAmount.size(); i++) { out.attributeInt(null, "dimUID" + index, wallpaper.mUidToDimAmount.keyAt(i)); out.attributeFloat(null, "dimValue" + index, wallpaper.mUidToDimAmount.valueAt(i)); index++; } } if (wallpaper.primaryColors != null) { int colorsCount = wallpaper.primaryColors.getMainColors().size(); out.attributeInt(null, "colorsCount", colorsCount); if (colorsCount > 0) { for (int i = 0; i < colorsCount; i++) { final Color wc = wallpaper.primaryColors.getMainColors().get(i); out.attributeInt(null, "colorValue" + i, wc.toArgb()); } } int allColorsCount = wallpaper.primaryColors.getAllColors().size(); out.attributeInt(null, "allColorsCount", allColorsCount); if (allColorsCount > 0) { int index = 0; for (Map.Entry<Integer, Integer> entry : wallpaper.primaryColors.getAllColors() .entrySet()) { out.attributeInt(null, "allColorsValue" + index, entry.getKey()); out.attributeInt(null, "allColorsPopulation" + index, entry.getValue()); index++; } } out.attributeInt(null, "colorHints", wallpaper.primaryColors.getColorHints()); } out.attribute(null, "name", wallpaper.name); if (wallpaper.wallpaperComponent != null && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) { out.attribute(null, "component", wallpaper.wallpaperComponent.flattenToShortString()); } if (wallpaper.allowBackup) { out.attributeBoolean(null, "backup", true); } out.endTag(null, tag); } // Restore the named resource bitmap to both source + crop files boolean restoreNamedResourceLocked(WallpaperData wallpaper) { if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) { String resName = wallpaper.name.substring(4); String pkg = null; int colon = resName.indexOf(':'); if (colon > 0) { pkg = resName.substring(0, colon); } String ident = null; int slash = resName.lastIndexOf('/'); if (slash > 0) { ident = resName.substring(slash + 1); } String type = null; if (colon > 0 && slash > 0 && (slash - colon) > 1) { type = resName.substring(colon + 1, slash); } if (pkg != null && ident != null && type != null) { int resId = -1; InputStream res = null; FileOutputStream fos = null; FileOutputStream cos = null; try { Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED); Resources r = c.getResources(); resId = r.getIdentifier(resName, null, null); if (resId == 0) { Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type + " ident=" + ident); return false; } res = r.openRawResource(resId); if (wallpaper.wallpaperFile.exists()) { wallpaper.wallpaperFile.delete(); wallpaper.cropFile.delete(); } fos = new FileOutputStream(wallpaper.wallpaperFile); cos = new FileOutputStream(wallpaper.cropFile); byte[] buffer = new byte[32768]; int amt; while ((amt = res.read(buffer)) > 0) { fos.write(buffer, 0, amt); cos.write(buffer, 0, amt); } // mWallpaperObserver will notice the close and send the change broadcast Slog.v(TAG, "Restored wallpaper: " + resName); return true; } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Package name " + pkg + " not found"); } catch (Resources.NotFoundException e) { Slog.e(TAG, "Resource not found: " + resId); } catch (IOException e) { Slog.e(TAG, "IOException while restoring wallpaper ", e); } finally { IoUtils.closeQuietly(res); if (fos != null) { FileUtils.sync(fos); } if (cos != null) { FileUtils.sync(cos); } IoUtils.closeQuietly(fos); IoUtils.closeQuietly(cos); } } } return false; } }
services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.view.DisplayInfo; import com.android.server.wm.WindowManagerInternal; import java.util.function.Consumer; /** * Internal class used to store all the display data relevant to the wallpapers */ Loading