diff options
| -rw-r--r-- | packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java | 232 | ||||
| -rw-r--r-- | packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java | 21 |
2 files changed, 253 insertions, 0 deletions
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java index f31eb44f23f5..23e269a67283 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.Context; 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.Pair; 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 @@ public class WallpaperBackupAgent extends BackupAgent { @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 @@ public class WallpaperBackupAgent extends BackupAgent { 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 @@ public class WallpaperBackupAgent extends BackupAgent { private boolean mSystemHasLiveComponent; private boolean mLockHasLiveComponent; + private DisplayManager mDisplayManager; + @Override public void onCreate() { if (DEBUG) { @@ -137,6 +155,8 @@ public class WallpaperBackupAgent extends BackupAgent { mBackupManager = new BackupManager(getBaseContext()); mEventLogger = new WallpaperEventLogger(mBackupManager, /* wallpaperAgent */ this); + + mDisplayManager = getSystemService(DisplayManager.class); } @Override @@ -175,9 +195,11 @@ public class WallpaperBackupAgent extends BackupAgent { 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 @@ public class WallpaperBackupAgent extends BackupAgent { } } + /** + * 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 @@ public class WallpaperBackupAgent extends BackupAgent { 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 @@ public class WallpaperBackupAgent extends BackupAgent { infoStage.delete(); imageStage.delete(); lockImageStage.delete(); + deviceDimensionsStage.delete(); SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); prefs.edit() @@ -409,6 +493,66 @@ public class WallpaperBackupAgent extends BackupAgent { } } + /** + * 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 @@ public class WallpaperBackupAgent extends BackupAgent { }; } + /** + * 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 3ecdf3f101a5..ec9223c7d667 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.Context; 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 @@ public class WallpaperBackupAgentTest { 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); |