Merge "Add device dimension data to wallpaper backup flow" into 24D1-dev
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index f31eb44..23e269a 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -39,7 +39,9 @@
import android.content.SharedPreferences;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -49,16 +51,22 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import android.view.Display;
+import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -102,6 +110,9 @@
@VisibleForTesting
static final String WALLPAPER_INFO_STAGE = "wallpaper-info-stage";
+ @VisibleForTesting
+ static final String WALLPAPER_BACKUP_DEVICE_INFO_STAGE = "wallpaper-backup-device-info-stage";
+
static final String EMPTY_SENTINEL = "empty";
static final String QUOTA_SENTINEL = "quota";
@@ -110,6 +121,11 @@
static final String SYSTEM_GENERATION = "system_gen";
static final String LOCK_GENERATION = "lock_gen";
+ /**
+ * An approximate area threshold to compare device dimension similarity
+ */
+ static final int AREA_THRESHOLD = 50; // TODO (b/327637867): determine appropriate threshold
+
// If this file exists, it means we exceeded our quota last time
private File mQuotaFile;
private boolean mQuotaExceeded;
@@ -121,6 +137,8 @@
private boolean mSystemHasLiveComponent;
private boolean mLockHasLiveComponent;
+ private DisplayManager mDisplayManager;
+
@Override
public void onCreate() {
if (DEBUG) {
@@ -137,6 +155,8 @@
mBackupManager = new BackupManager(getBaseContext());
mEventLogger = new WallpaperEventLogger(mBackupManager, /* wallpaperAgent */ this);
+
+ mDisplayManager = getSystemService(DisplayManager.class);
}
@Override
@@ -175,9 +195,11 @@
mSystemHasLiveComponent = mWallpaperManager.getWallpaperInfo(FLAG_SYSTEM) != null;
mLockHasLiveComponent = mWallpaperManager.getWallpaperInfo(FLAG_LOCK) != null;
+ // performing backup of each file based on order of importance
backupWallpaperInfoFile(/* sysOrLockChanged= */ sysChanged || lockChanged, data);
backupSystemWallpaperFile(sharedPrefs, sysChanged, sysGeneration, data);
backupLockWallpaperFileIfItExists(sharedPrefs, lockChanged, lockGeneration, data);
+ backupDeviceInfoFile(data);
} catch (Exception e) {
Slog.e(TAG, "Unable to back up wallpaper", e);
mEventLogger.onBackupException(e);
@@ -191,6 +213,54 @@
}
}
+ /**
+ * This method backs up the device dimension information. The device data will always get
+ * overwritten when triggering a backup
+ */
+ private void backupDeviceInfoFile(FullBackupDataOutput data)
+ throws IOException {
+ final File deviceInfoStage = new File(getFilesDir(), WALLPAPER_BACKUP_DEVICE_INFO_STAGE);
+
+ // save the dimensions of the device with xml formatting
+ Point dimensions = getScreenDimensions();
+ Display smallerDisplay = getSmallerDisplayIfExists();
+ Point secondaryDimensions = smallerDisplay != null ? getRealSize(smallerDisplay) :
+ new Point(0, 0);
+
+ deviceInfoStage.createNewFile();
+ FileOutputStream fstream = new FileOutputStream(deviceInfoStage, false);
+ TypedXmlSerializer out = Xml.resolveSerializer(fstream);
+ out.startDocument(null, true);
+ out.startTag(null, "dimensions");
+
+ out.startTag(null, "width");
+ out.text(String.valueOf(dimensions.x));
+ out.endTag(null, "width");
+
+ out.startTag(null, "height");
+ out.text(String.valueOf(dimensions.y));
+ out.endTag(null, "height");
+
+ if (smallerDisplay != null) {
+ out.startTag(null, "secondarywidth");
+ out.text(String.valueOf(secondaryDimensions.x));
+ out.endTag(null, "secondarywidth");
+
+ out.startTag(null, "secondaryheight");
+ out.text(String.valueOf(secondaryDimensions.y));
+ out.endTag(null, "secondaryheight");
+ }
+
+ out.endTag(null, "dimensions");
+ out.endDocument();
+ fstream.flush();
+ FileUtils.sync(fstream);
+ fstream.close();
+
+ if (DEBUG) Slog.v(TAG, "Storing device dimension data");
+ backupFile(deviceInfoStage, data);
+ }
+
private void backupWallpaperInfoFile(boolean sysOrLockChanged, FullBackupDataOutput data)
throws IOException {
final ParcelFileDescriptor wallpaperInfoFd = mWallpaperManager.getWallpaperInfoFile();
@@ -364,9 +434,22 @@
final File infoStage = new File(filesDir, WALLPAPER_INFO_STAGE);
final File imageStage = new File(filesDir, SYSTEM_WALLPAPER_STAGE);
final File lockImageStage = new File(filesDir, LOCK_WALLPAPER_STAGE);
+ final File deviceDimensionsStage = new File(filesDir, WALLPAPER_BACKUP_DEVICE_INFO_STAGE);
boolean lockImageStageExists = lockImageStage.exists();
try {
+ // Parse the device dimensions of the source device and compare with target to
+ // to identify whether we need to skip the remainder of the restore process
+ Pair<Point, Point> sourceDeviceDimensions = parseDeviceDimensions(
+ deviceDimensionsStage);
+
+ Point targetDeviceDimensions = getScreenDimensions();
+ if (sourceDeviceDimensions != null && targetDeviceDimensions != null
+ && isSourceDeviceSignificantlySmallerThanTarget(sourceDeviceDimensions.first,
+ targetDeviceDimensions)) {
+ Slog.d(TAG, "The source device is significantly smaller than target");
+ }
+
// First parse the live component name so that we know for logging if we care about
// logging errors with the image restore.
ComponentName wpService = parseWallpaperComponent(infoStage, "wp");
@@ -400,6 +483,7 @@
infoStage.delete();
imageStage.delete();
lockImageStage.delete();
+ deviceDimensionsStage.delete();
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
prefs.edit()
@@ -409,6 +493,66 @@
}
}
+ /**
+ * This method parses the given file for the backed up device dimensions
+ *
+ * @param deviceDimensions the file which holds the device dimensions
+ * @return the backed up device dimensions
+ */
+ private Pair<Point, Point> parseDeviceDimensions(File deviceDimensions) {
+ int width = 0, height = 0, secondaryHeight = 0, secondaryWidth = 0;
+ try {
+ TypedXmlPullParser parser = Xml.resolvePullParser(
+ new FileInputStream(deviceDimensions));
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+
+ switch (name) {
+ case "width":
+ String widthText = readText(parser);
+ width = Integer.valueOf(widthText);
+ break;
+
+ case "height":
+ String textHeight = readText(parser);
+ height = Integer.valueOf(textHeight);
+ break;
+
+ case "secondarywidth":
+ String secondaryWidthText = readText(parser);
+ secondaryWidth = Integer.valueOf(secondaryWidthText);
+ break;
+
+ case "secondaryheight":
+ String secondaryHeightText = readText(parser);
+ secondaryHeight = Integer.valueOf(secondaryHeightText);
+ break;
+ default:
+ break;
+ }
+ }
+ return new Pair<>(new Point(width, height), new Point(secondaryWidth, secondaryHeight));
+
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static String readText(TypedXmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String result = "";
+ if (parser.next() == XmlPullParser.TEXT) {
+ result = parser.getText();
+ parser.nextTag();
+ }
+ return result;
+ }
+
@VisibleForTesting
void updateWallpaperComponent(ComponentName wpService, int which)
throws IOException {
@@ -691,6 +835,94 @@
};
}
+ /**
+ * This method retrieves the dimensions of the largest display of the device
+ *
+ * @return a @{Point} object that contains the dimensions of the largest display on the device
+ */
+ private Point getScreenDimensions() {
+ Point largetDimensions = null;
+ int maxArea = 0;
+
+ for (Display display : getInternalDisplays()) {
+ Point displaySize = getRealSize(display);
+
+ int width = displaySize.x;
+ int height = displaySize.y;
+ int area = width * height;
+
+ if (area > maxArea) {
+ maxArea = area;
+ largetDimensions = displaySize;
+ }
+ }
+
+ return largetDimensions;
+ }
+
+ private Point getRealSize(Display display) {
+ DisplayInfo displayInfo = new DisplayInfo();
+ display.getDisplayInfo(displayInfo);
+ return new Point(displayInfo.logicalWidth, displayInfo.logicalHeight);
+ }
+
+ /**
+ * This method returns the smaller display on a multi-display device
+ *
+ * @return Display that corresponds to the smaller display on a device or null if ther is only
+ * one Display on a device
+ */
+ private Display getSmallerDisplayIfExists() {
+ List<Display> internalDisplays = getInternalDisplays();
+ Point largestDisplaySize = getScreenDimensions();
+
+ // Find the first non-matching internal display
+ for (Display display : internalDisplays) {
+ Point displaySize = getRealSize(display);
+ if (displaySize.x != largestDisplaySize.x || displaySize.y != largestDisplaySize.y) {
+ return display;
+ }
+ }
+
+ // If no smaller display found, return null, as there is only a single display
+ return null;
+ }
+
+ /**
+ * This method retrieves the collection of Display objects available in the device.
+ * i.e. non-external displays are ignored
+ *
+ * @return list of displays corresponding to each display in the device
+ */
+ private List<Display> getInternalDisplays() {
+ Display[] allDisplays = mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+
+ List<Display> internalDisplays = new ArrayList<>();
+ for (Display display : allDisplays) {
+ if (display.getType() == Display.TYPE_INTERNAL) {
+ internalDisplays.add(display);
+ }
+ }
+ return internalDisplays;
+ }
+
+ /**
+ * This method compares the source and target dimensions, and returns true if there is a
+ * significant difference in area between them and the source dimensions are smaller than the
+ * target dimensions.
+ *
+ * @param sourceDimensions is the dimensions of the source device
+ * @param targetDimensions is the dimensions of the target device
+ */
+ @VisibleForTesting
+ boolean isSourceDeviceSignificantlySmallerThanTarget(Point sourceDimensions,
+ Point targetDimensions) {
+ int rawAreaDelta = (targetDimensions.x * targetDimensions.y)
+ - (sourceDimensions.x * sourceDimensions.y);
+ return rawAreaDelta > AREA_THRESHOLD;
+ }
+
@VisibleForTesting
boolean isDeviceInRestore() {
try {
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index 3ecdf3f..ec9223c 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -59,6 +59,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -840,6 +841,26 @@
testParseCropHints(testMap);
}
+ @Test
+ public void test_sourceDimensionsAreLargerThanTarget() {
+ // source device is larger than target, expecting to get false
+ Point sourceDimensions = new Point(2208, 1840);
+ Point targetDimensions = new Point(1080, 2092);
+ boolean isSourceSmaller = mWallpaperBackupAgent
+ .isSourceDeviceSignificantlySmallerThanTarget(sourceDimensions, targetDimensions);
+ assertThat(isSourceSmaller).isEqualTo(false);
+ }
+
+ @Test
+ public void test_sourceDimensionsMuchSmallerThanTarget() {
+ // source device is smaller than target, expecting to get true
+ Point sourceDimensions = new Point(1080, 2092);
+ Point targetDimensions = new Point(2208, 1840);
+ boolean isSourceSmaller = mWallpaperBackupAgent
+ .isSourceDeviceSignificantlySmallerThanTarget(sourceDimensions, targetDimensions);
+ assertThat(isSourceSmaller).isEqualTo(true);
+ }
+
private void testParseCropHints(Map<Integer, Rect> testMap) throws Exception {
assumeTrue(multiCrop());
mockRestoredStaticWallpaperFile(testMap);