Support scoped storage
Change how bitmaps are dumped to use app-local storage
which needs no permissions combined with the latest
& greatest pull-pattern-keys method of specifying
files to be pulled by FilePullerLogCollector
Bug: 154630865
Test: this
Change-Id: Ia25e7be625d2590181b9713ba482b12ce00f5d56
diff --git a/tests/tests/uirendering/AndroidManifest.xml b/tests/tests/uirendering/AndroidManifest.xml
index f43818a..ce0e2a3 100644
--- a/tests/tests/uirendering/AndroidManifest.xml
+++ b/tests/tests/uirendering/AndroidManifest.xml
@@ -20,7 +20,6 @@
android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<!--
* Some tests (e.g. ShadowTests#testShadowLayout) may have different results depending on
@@ -32,8 +31,7 @@
android:theme="@style/DefaultTheme"
android:screenOrientation="locked"
android:resizeableActivity="false"
- android:configChanges="uiMode"
- android:requestLegacyExternalStorage="true" />
+ android:configChanges="uiMode" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/tests/uirendering/AndroidTest.xml b/tests/tests/uirendering/AndroidTest.xml
index 150c7c5..dd40bca 100644
--- a/tests/tests/uirendering/AndroidTest.xml
+++ b/tests/tests/uirendering/AndroidTest.xml
@@ -27,12 +27,10 @@
<option name="package" value="android.uirendering.cts" />
<option name="runtime-hint" value="11m55s" />
<option name="runner" value="android.uirendering.cts.runner.UiRenderingRunner" />
- <option name="isolated-storage" value="false" />
</test>
- <!-- Collect the files in the dump directory for debugging -->
+ <!-- Collect the dumped files for debugging -->
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/sdcard/UiRenderingCaptures" />
- <option name="collect-on-run-ended-only" value="true" />
+ <option name="pull-pattern-keys" value="uirendering_.*" />
</metrics_collector>
</configuration>
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/runner/UiRenderingRunner.java b/tests/tests/uirendering/src/android/uirendering/cts/runner/UiRenderingRunner.java
index 0215e16..c161d49 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/runner/UiRenderingRunner.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/runner/UiRenderingRunner.java
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.support.test.uiautomator.UiDevice;
+import android.uirendering.cts.util.BitmapDumper;
import androidx.test.runner.AndroidJUnitRunner;
@@ -43,6 +44,8 @@
getContext().sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
} catch (Exception e) {
}
+
+ BitmapDumper.initialize(this);
}
@Override
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
index 55adc11..3b3a12e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
@@ -34,14 +34,6 @@
public BitmapAsserter(String className, String name) {
mClassName = className;
mDifferenceVisualizer = new PassFailVisualizer();
-
- // Create a location for the files to be held, if it doesn't exist already
- BitmapDumper.createSubDirectory(mClassName);
-
- // If we have a test currently, let's remove the older files if they exist
- if (name != null) {
- BitmapDumper.deleteFileInClassFolder(mClassName, name);
- }
}
/**
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
index 5c59c46..db5458f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
@@ -15,53 +15,74 @@
*/
package android.uirendering.cts.util;
+import android.app.Instrumentation;
import android.graphics.Bitmap;
-import android.os.Environment;
+import android.os.Bundle;
import android.uirendering.cts.differencevisualizers.DifferenceVisualizer;
import android.util.Log;
-import com.android.compatibility.common.util.BitmapUtils;
-
import java.io.File;
+import java.io.FileOutputStream;
/**
* A utility class that will allow the user to save bitmaps to the sdcard on the device.
*/
public final class BitmapDumper {
- private final static String TAG = "BitmapDumper";
- private final static String IDEAL_RENDERING_FILE_NAME = "idealCapture.png";
- private final static String TESTED_RENDERING_FILE_NAME = "testedCapture.png";
- private final static String VISUALIZER_RENDERING_FILE_NAME = "visualizer.png";
- private final static String SINGULAR_FILE_NAME = "capture.png";
- private final static String CAPTURE_SUB_DIRECTORY = Environment.getExternalStorageDirectory()
- + "/UiRenderingCaptures/";
+ private static final String TAG = "BitmapDumper";
+ private static final String KEY_PREFIX = "uirendering_";
+ private static final String TYPE_IDEAL_RENDERING = "idealCapture";
+ private static final String TYPE_TESTED_RENDERING = "testedCapture";
+ private static final String TYPE_VISUALIZER_RENDERING = "visualizer";
+ private static final String TYPE_SINGULAR = "capture";
+
+ // Magic number for an in-progress status report
+ private static final int INST_STATUS_IN_PROGRESS = 2;
+ private static File sDumpDirectory;
+ private static Instrumentation sInstrumentation;
private BitmapDumper() {}
- /**
- * Deletes the specific files for the given test in a given class.
- */
- public static void deleteFileInClassFolder(String className, String testName) {
- File directory = new File(CAPTURE_SUB_DIRECTORY + className);
+ public static void initialize(Instrumentation instrumentation) {
+ sInstrumentation = instrumentation;
+ sDumpDirectory = instrumentation.getContext().getExternalCacheDir();
- String[] children = directory.list();
- if (children == null) {
- return;
- }
- for (String file : children) {
- if (file.startsWith(testName)) {
- new File(directory, file).delete();
- }
+ // Cleanup old tests
+ // These are removed on uninstall anyway but just in case...
+ File[] toRemove = sDumpDirectory.listFiles();
+ for (File file : toRemove) {
+ deleteContentsAndDir(file);
}
}
- public static void createSubDirectory(String className) {
- File saveDirectory = new File(CAPTURE_SUB_DIRECTORY + className);
- if (saveDirectory.exists()) {
- return;
+ private static boolean deleteContentsAndDir(File dir) {
+ if (deleteContents(dir)) {
+ return dir.delete();
+ } else {
+ return false;
}
- // Create the directory if it isn't already created.
- saveDirectory.mkdirs();
+ }
+
+ private static boolean deleteContents(File dir) {
+ File[] files = dir.listFiles();
+ boolean success = true;
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory()) {
+ success &= deleteContents(file);
+ }
+ if (!file.delete()) {
+ Log.w(TAG, "Failed to delete " + file);
+ success = false;
+ }
+ }
+ }
+ return success;
+ }
+
+ private static File getFile(String className, String testName, String type) {
+ File testDirectory = new File(sDumpDirectory, className);
+ testDirectory.mkdirs();
+ return new File(testDirectory, testName + "_" + type + ".png");
}
/**
@@ -85,9 +106,18 @@
visualizerBitmap.setPixels(visualizerArray, 0, width, 0, 0, width, height);
Bitmap croppedBitmap = Bitmap.createBitmap(testedBitmap, 0, 0, width, height);
- saveFile(className, testName, IDEAL_RENDERING_FILE_NAME, idealBitmap);
- saveFile(className, testName, TESTED_RENDERING_FILE_NAME, croppedBitmap);
- saveFile(className, testName, VISUALIZER_RENDERING_FILE_NAME, visualizerBitmap);
+ File idealFile = getFile(className, testName, TYPE_IDEAL_RENDERING);
+ File testedFile = getFile(className, testName, TYPE_TESTED_RENDERING);
+ File visualizerFile = getFile(className, testName, TYPE_VISUALIZER_RENDERING);
+ saveBitmap(idealBitmap, idealFile);
+ saveBitmap(croppedBitmap, testedFile);
+ saveBitmap(visualizerBitmap, visualizerFile);
+
+ Bundle report = new Bundle();
+ report.putString(KEY_PREFIX + TYPE_IDEAL_RENDERING, idealFile.getAbsolutePath());
+ report.putString(KEY_PREFIX + TYPE_TESTED_RENDERING, testedFile.getAbsolutePath());
+ report.putString(KEY_PREFIX + TYPE_VISUALIZER_RENDERING, visualizerFile.getAbsolutePath());
+ sInstrumentation.sendStatus(INST_STATUS_IN_PROGRESS, report);
}
public static void dumpBitmap(Bitmap bitmap, String testName, String className) {
@@ -95,11 +125,39 @@
Log.d(TAG, "File not saved, bitmap was null for test : " + testName);
return;
}
- saveFile(className, testName, SINGULAR_FILE_NAME, bitmap);
+ File capture = getFile(className, testName, TYPE_SINGULAR);
+ saveBitmap(bitmap, capture);
+ Bundle report = new Bundle();
+ report.putString(KEY_PREFIX + TYPE_SINGULAR, capture.getAbsolutePath());
+ sInstrumentation.sendStatus(INST_STATUS_IN_PROGRESS, report);
}
- private static void saveFile(String className, String testName, String fileName, Bitmap bitmap) {
- BitmapUtils.saveBitmap(bitmap, CAPTURE_SUB_DIRECTORY + className,
- testName + "_" + fileName);
+ private static void logIfBitmapSolidColor(String fileName, Bitmap bitmap) {
+ int firstColor = bitmap.getPixel(0, 0);
+ for (int x = 0; x < bitmap.getWidth(); x++) {
+ for (int y = 0; y < bitmap.getHeight(); y++) {
+ if (bitmap.getPixel(x, y) != firstColor) {
+ return;
+ }
+ }
+ }
+
+ Log.w(TAG, String.format("%s entire bitmap color is %x", fileName, firstColor));
+ }
+
+ private static void saveBitmap(Bitmap bitmap, File file) {
+ if (bitmap == null) {
+ Log.d(TAG, "File not saved, bitmap was null");
+ return;
+ }
+
+ logIfBitmapSolidColor(file.getName(), bitmap);
+
+ try (FileOutputStream fileStream = new FileOutputStream(file)) {
+ bitmap.compress(Bitmap.CompressFormat.PNG, 0 /* ignored for PNG */, fileStream);
+ fileStream.flush();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
}