Merge "Camera: Handle case where BatteryInfo intent not available" into qt-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2513993..92a100b 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -16,6 +16,7 @@
tests/tests/content/
tests/tests/graphics/
tests/tests/hardware/
+ tests/tests/permission2/
tests/tests/preference/
tests/tests/print/
tests/tests/text/
diff --git a/apps/CtsVerifier/res/layout/cf_main.xml b/apps/CtsVerifier/res/layout/cf_main.xml
index 1ff35cc..8a4fb7f 100644
--- a/apps/CtsVerifier/res/layout/cf_main.xml
+++ b/apps/CtsVerifier/res/layout/cf_main.xml
@@ -87,6 +87,11 @@
android:id="@+id/format_selection"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
+ <Button
+ android:id="@+id/next_button"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/cf_next_button" />
</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 3ecfab7..50eac36 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1318,10 +1318,12 @@
the right view must be horizontally mirrored relative to the left
view.\n - Note that the frame rate of the right view may be much
lower than on the left; this is not an indication of a failed
- test.
+ test.\n - The next button triggers the next resolution and format
+ combination of the current camera to show; this is optional.
</string>
<string name="cf_preview_label">Normal preview</string>
<string name="cf_format_label">Processed callback data</string>
+ <string name="cf_next_button">Next</string>
<!-- Strings for Camera Video -->
<string name="record_button_text">Test</string>
@@ -4990,6 +4992,10 @@
BubbleMetadata is configured on the notification and user actions. Bubbles are special
notifications that appear as a floating button on the screen, in addition to the notification
in the notification shade.</string>
+ <string name="bubbles_notification_test_enable_bubbles_title">Enable Bubbles for CTS Verifier</string>
+ <string name="bubbles_notification_test_enable_bubbles_verify">Click the button below and enable
+ bubbles for the verifier app on the resulting screen, if they aren\'t enabled already.</string>
+ <string name="bubbles_notification_enable_bubbles_button">Enable bubbles for CTS Verifier</string>
<string name="bubbles_notification_test_title_1">Step 1: send a bubble with notification</string>
<string name="bubbles_notification_test_verify_1">Click the button below and verify that there is a
bubble on the screen and a notification in the notification shade.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
index 72c54c2..9b54ed3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
@@ -94,9 +94,6 @@
}
});
- mPolicyItems.add(new PasswordQualityPolicy(this));
- mPolicyItems.add(new PasswordMinimumLengthPolicy(this));
-
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
mPolicyItems.add(new MaximumFailedPasswordsForWipePolicy(this));
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
index 9c5b31d..3421f65 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
@@ -40,6 +40,7 @@
import android.view.TextureView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Spinner;
@@ -51,6 +52,7 @@
import java.util.HashSet;
import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
import java.util.TreeSet;
/**
@@ -99,14 +101,39 @@
private boolean mProcessInProgress = false;
private boolean mProcessingFirstFrame = false;
- private TreeSet<String> mTestedCombinations = new TreeSet<String>();
- private TreeSet<String> mUntestedCombinations = new TreeSet<String>();
+ private final TreeSet<CameraCombination> mTestedCombinations = new TreeSet<>(COMPARATOR);
+ private final TreeSet<CameraCombination> mUntestedCombinations = new TreeSet<>(COMPARATOR);
private int mAllCombinationsSize = 0;
// Menu to show the test progress
private static final int MENU_ID_PROGRESS = Menu.FIRST + 1;
+ private class CameraCombination {
+ private final int cameraIndex;
+ private final int resolutionIndex;
+ private final int formatIndex;
+
+ private CameraCombination(int cameraIndex, int resolutionIndex, int formatIndex) {
+ this.cameraIndex = cameraIndex;
+ this.resolutionIndex = resolutionIndex;
+ this.formatIndex = formatIndex;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Camera %d, %dx%d, %s", cameraIndex,
+ mPreviewSizes.get(resolutionIndex).width,
+ mPreviewSizes.get(resolutionIndex).height,
+ mPreviewFormatNames.get(mPreviewFormats.get(formatIndex)));
+ }
+ }
+
+ private static final Comparator<CameraCombination> COMPARATOR =
+ Comparator.<CameraCombination, Integer>comparing(c -> c.cameraIndex)
+ .thenComparing(c -> c.resolutionIndex)
+ .thenComparing(c -> c.formatIndex);
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -130,7 +157,6 @@
String[] cameraNames = new String[numCameras];
for (int i = 0; i < numCameras; i++) {
cameraNames[i] = "Camera " + i;
- mUntestedCombinations.add("All combinations for Camera " + i + "\n");
}
mCameraSpinner = (Spinner) findViewById(R.id.cameras_selection);
mCameraSpinner.setAdapter(
@@ -171,6 +197,35 @@
yTotal.setConcat(y2r, yOffset);
mYuv2RgbFilter = new ColorMatrixColorFilter(yTotal);
+
+ Button mNextButton = findViewById(R.id.next_button);
+ mNextButton.setOnClickListener(v -> {
+ setUntestedCombination();
+ startPreview();
+ });
+ }
+
+ /**
+ * Set an untested combination of resolution and format for the current camera.
+ * Triggered by next button click.
+ */
+ private void setUntestedCombination() {
+ Optional<CameraCombination> combination = mUntestedCombinations.stream().filter(
+ c -> c.cameraIndex == mCurrentCameraId).findFirst();
+ if (!combination.isPresent()) {
+ Toast.makeText(this, "All Camera " + mCurrentCameraId + " tests are done.",
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // There is untested combination for the current camera, set the next untested combination.
+ int mResolutionIndex = combination.get().resolutionIndex;
+ int mFormatIndex = combination.get().formatIndex;
+
+ mNextPreviewSize = mPreviewSizes.get(mResolutionIndex);
+ mResolutionSpinner.setSelection(mResolutionIndex);
+ mNextPreviewFormat = mPreviewFormats.get(mFormatIndex);
+ mFormatSpinner.setSelection(mFormatIndex);
}
@Override
@@ -183,13 +238,13 @@
public boolean onOptionsItemSelected(MenuItem item) {
boolean ret = true;
switch (item.getItemId()) {
- case MENU_ID_PROGRESS:
- showCombinationsDialog();
- ret = true;
- break;
- default:
- ret = super.onOptionsItemSelected(item);
- break;
+ case MENU_ID_PROGRESS:
+ showCombinationsDialog();
+ ret = true;
+ break;
+ default:
+ ret = super.onOptionsItemSelected(item);
+ break;
}
return ret;
}
@@ -222,17 +277,19 @@
public String getTestDetails() {
StringBuilder reportBuilder = new StringBuilder();
reportBuilder.append("Tested combinations:\n");
- for (String combination: mTestedCombinations) {
+ for (CameraCombination combination: mTestedCombinations) {
reportBuilder.append(combination);
+ reportBuilder.append("\n");
}
+
reportBuilder.append("Untested combinations:\n");
- for (String combination: mUntestedCombinations) {
+ for (CameraCombination combination: mUntestedCombinations) {
reportBuilder.append(combination);
+ reportBuilder.append("\n");
}
return reportBuilder.toString();
}
-
public void onSurfaceTextureAvailable(SurfaceTexture surface,
int width, int height) {
mPreviewTexture = surface;
@@ -240,7 +297,7 @@
|| mFormatView.getMeasuredHeight() != height) {
mPreviewTexWidth = mFormatView.getMeasuredWidth();
mPreviewTexHeight = mFormatView.getMeasuredHeight();
- } else {
+ } else {
mPreviewTexWidth = width;
mPreviewTexHeight = height;
}
@@ -310,8 +367,6 @@
};
-
-
private void setUpCamera(int id) {
shutdownCamera();
@@ -331,7 +386,7 @@
if (lhs.height > rhs.height) return 1;
return 0;
}
- };
+ }
SizeCompare s = new SizeCompare();
TreeSet<Camera.Size> sortedResolutions = new TreeSet<Camera.Size>(s);
@@ -365,13 +420,11 @@
// Update untested entries
- mUntestedCombinations.remove("All combinations for Camera " + id + "\n");
- for (Camera.Size previewSize: mPreviewSizes) {
- for (int previewFormat: mPreviewFormats) {
- String combination = "Camera " + id + ", "
- + previewSize.width + "x" + previewSize.height
- + ", " + mPreviewFormatNames.get(previewFormat)
- + "\n";
+ for (int resolutionIndex = 0; resolutionIndex < mPreviewSizes.size(); resolutionIndex++) {
+ for (int formatIndex = 0; formatIndex < mPreviewFormats.size(); formatIndex++) {
+ CameraCombination combination = new CameraCombination(
+ id, resolutionIndex, formatIndex);
+
if (!mTestedCombinations.contains(combination)) {
mUntestedCombinations.add(combination);
}
@@ -571,14 +624,16 @@
mFormatView.setImageBitmap(mCallbackBitmap);
if (mProcessingFirstFrame) {
mProcessingFirstFrame = false;
- String combination = "Camera " + mCurrentCameraId + ", "
- + mPreviewSize.width + "x" + mPreviewSize.height
- + ", " + mPreviewFormatNames.get(mPreviewFormat)
- + "\n";
+
+ CameraCombination combination = new CameraCombination(
+ mCurrentCameraId,
+ mResolutionSpinner.getSelectedItemPosition(),
+ mFormatSpinner.getSelectedItemPosition());
+
mUntestedCombinations.remove(combination);
mTestedCombinations.add(combination);
- displayToast(combination.replace("\n", ""));
+ displayToast(combination.toString());
if (mTestedCombinations.size() == mAllCombinationsSize) {
setPassButtonEnabled(true);
@@ -617,7 +672,8 @@
}
private void displayToast(String combination) {
- Toast.makeText(this, "\"" + combination + "\"\n" + " has been tested.", Toast.LENGTH_LONG).show();
+ Toast.makeText(this, "\"" + combination + "\"\n" + " has been tested.", Toast.LENGTH_SHORT)
+ .show();
}
public void onPreviewFrame(byte[] data, Camera camera) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
index d5c81fe..fd1c457 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
@@ -29,6 +29,7 @@
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.os.Bundle;
+import android.provider.Settings;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
@@ -100,6 +101,7 @@
runNextTestOrShowSummary();
});
+ mTests.add(new EnableBubbleTest());
mTests.add(new SendBubbleTest());
mTests.add(new SuppressNotifTest());
mTests.add(new AddNotifTest());
@@ -178,6 +180,38 @@
}
}
+ private class EnableBubbleTest extends BubblesTestStep {
+
+ @Override
+ public int getButtonText() {
+ return R.string.bubbles_notification_enable_bubbles_button;
+ }
+
+
+ @Override
+ public int getTestTitle() {
+ return R.string.bubbles_notification_test_enable_bubbles_title;
+ }
+
+ @Override
+ public int getTestDescription() {
+ return R.string.bubbles_notification_test_enable_bubbles_verify;
+ }
+
+ @Override
+ public void performTestAction() {
+ final String packageName = getApplicationContext().getPackageName();
+ final int appUid = getApplicationInfo().uid;
+ final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
+ intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+ intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ startActivity(intent);
+ }
+ }
+
private class SendBubbleTest extends BubblesTestStep {
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
index a3de878..1b14d2b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
@@ -304,7 +304,14 @@
if (!TextUtils.isEmpty(id)) {
AutomaticZenRule rule = mNm.getAutomaticZenRule(id);
- if (Objects.equals(ruleToCreate, rule)) {
+ if (rule != null && ruleToCreate.getName().equals(rule.getName())
+ && ruleToCreate.getOwner().equals(rule.getOwner())
+ && ruleToCreate.getConditionId().equals(rule.getConditionId())
+ && ruleToCreate.isEnabled() == rule.isEnabled()
+ && ruleToCreate.getInterruptionFilter() == rule.getInterruptionFilter()
+ && Objects.equals(ruleToCreate.getConfigurationActivity(),
+ rule.getConfigurationActivity())
+ && Objects.equals(ruleToCreate.getZenPolicy(), rule.getZenPolicy())) {
status = PASS;
} else {
logFail("created rule doesn't equal actual rule");
diff --git a/apps/OomCatcher/Android.mk b/apps/OomCatcher/Android.mk
index 7f47e03..e14cde5 100644
--- a/apps/OomCatcher/Android.mk
+++ b/apps/OomCatcher/Android.mk
@@ -27,7 +27,7 @@
LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
index 23df503..93f6f19 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk
index 11f8674..2faf2d4 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgradeWrongSHA.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
index fc9f02e..f0cc8b6 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk
index bf49682..d7e0826 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgradeWrongSHA.apk
Binary files differ
diff --git a/hostsidetests/devicepolicy/app/DeviceAdmin/api29/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAdmin/api29/AndroidManifest.xml
index a0bf3c0..326e61f 100644
--- a/hostsidetests/devicepolicy/app/DeviceAdmin/api29/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAdmin/api29/AndroidManifest.xml
@@ -17,8 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.deviceadmin29" >
- <!-- STOPSHIP(b/114173216): Uncomment this once Q's API level is finalized -->
- <!--<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="29"/>-->
+ <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="29"/>
<application
android:testOnly="true">
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
index e6bf9c0..1cbf5b2 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
@@ -53,14 +53,6 @@
InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND);
}
- public void testInstallUpdate_failWrongVersion() throws InterruptedException {
- assertUpdateError(
- "wrongVersion.zip",
- isDeviceAB()
- ? InstallSystemUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION
- : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
- }
-
public void testInstallUpdate_failNoZipOtaFile() throws InterruptedException {
assertUpdateError("notZip.zi",
isDeviceAB()
diff --git a/hostsidetests/devicepolicy/res/wrongVersion.zip b/hostsidetests/devicepolicy/res/wrongVersion.zip
deleted file mode 100644
index 3dfcfa8..0000000
--- a/hostsidetests/devicepolicy/res/wrongVersion.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index f26733c..6130759 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -549,6 +549,8 @@
Collections.singletonMap(ARG_NETWORK_LOGGING_BATCH_COUNT, Integer.toString(1)));
// Reboot the device, so the security event IDs are re-set.
rebootAndWaitUntilReady();
+ // Make sure BOOT_COMPLETED is completed before proceeding.
+ waitForBroadcastIdle();
// First batch after reboot: retrieve and verify the events.
executeDeviceTestMethod(".NetworkLoggingTest", "testNetworkLoggingAndRetrieval",
Collections.singletonMap(ARG_NETWORK_LOGGING_BATCH_COUNT, Integer.toString(1)));
@@ -1028,7 +1030,6 @@
return;
}
- pushUpdateFileToDevice("wrongVersion.zip");
pushUpdateFileToDevice("notZip.zi");
pushUpdateFileToDevice("empty.zip");
pushUpdateFileToDevice("wrongPayload.zip");
diff --git a/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java b/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
index c7a75a7..1e8040d 100644
--- a/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
+++ b/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
@@ -292,4 +292,42 @@
// At this point, the host test driver will reboot the device to complete the uninstall.
}
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ * Enable rollback phase.
+ */
+ @Test
+ public void testApexRollbackExpirationEnableRollback() throws Exception {
+ assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+
+ Install.single(TestApp.Apex2).setStaged().setEnableRollback().commit();
+
+ // At this point, the host test driver will reboot the device and run
+ // testApexRollbackExpirationUpdateApex().
+ }
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ * Update apex phase.
+ */
+ @Test
+ public void testApexRollbackExpirationUpdateApex() throws Exception {
+ assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+ assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNotNull();
+ Install.single(TestApp.Apex3).setStaged().commit();
+
+ // At this point, the host test driver will reboot the device and run
+ // testApexRollbackExpirationConfirmExpiration().
+ }
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ * Confirm expiration phase.
+ */
+ @Test
+ public void testApexRollbackExpirationConfirmExpiration() throws Exception {
+ assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNull();
+ }
}
diff --git a/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java b/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
index e9192dd..60e154c 100644
--- a/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
+++ b/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
@@ -147,4 +147,20 @@
getDevice().reboot();
run("testApexAndApkConfirmRollback");
}
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ */
+ @Test
+ public void testApexRollbackExpiration() throws Exception {
+ assumeTrue("Device does not support updating APEX", isApexUpdateSupported());
+
+ uninstallShimApexIfNecessary();
+ run("testApexRollbackExpirationEnableRollback");
+ getDevice().reboot();
+ run("testApexRollbackExpirationUpdateApex");
+ getDevice().reboot();
+ run("testApexRollbackExpirationConfirmExpiration");
+ }
+
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk
index e9ffee4..0bd5a7c 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk
@@ -21,7 +21,7 @@
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 68f06d5..6ddd9f1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -141,6 +141,7 @@
if (deviceToReboot != null) {
deviceToReboot.nonBlockingReboot();
deviceToReboot.waitForDeviceAvailable();
+ updateKernelStartTime();
}
}
fail("\"" + ptr + "\" is an exposed kernel pointer.");
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
index 388fd0a..71c34c2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -16,6 +16,7 @@
package android.accessibilityservice.cts;
+import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangeTypesAndWindowTitle;
import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangedWithChangeTypes;
import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.findWindowByTitle;
import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.getActivityTitle;
@@ -275,8 +276,8 @@
autoCompleteTextView.setAdapter(adapter);
autoCompleteTextView.showDropDown();
}),
- filterWindowsChangedWithChangeTypes(WINDOWS_CHANGE_CHILDREN),
- TIMEOUT_ASYNC_PROCESSING);
+ filterWindowsChangeTypesAndWindowTitle(sUiAutomation, WINDOWS_CHANGE_CHILDREN,
+ mActivityTitle.toString()), TIMEOUT_ASYNC_PROCESSING);
} catch (TimeoutException exception) {
throw new RuntimeException(
"Failed to get window changed event when showing dropdown", exception);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
index 3da457a..790246e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
@@ -14,13 +14,20 @@
package android.accessibilityservice.cts.utils;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.both;
+
+import android.app.UiAutomation;
import android.app.UiAutomation.AccessibilityEventFilter;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+import androidx.annotation.NonNull;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
+import java.util.List;
import java.util.function.BiPredicate;
/**
@@ -45,6 +52,13 @@
return (both(new AccessibilityEventTypeMatcher(eventType)).and(matchResourceName))::matches;
}
+ public static AccessibilityEventFilter filterWindowsChangeTypesAndWindowTitle(
+ @NonNull UiAutomation uiAutomation, int changeTypes, @NonNull String title) {
+ return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
+ new WindowChangesMatcher(changeTypes),
+ new WindowTitleMatcher(uiAutomation, title))::matches;
+ }
+
public static class AccessibilityEventTypeMatcher extends TypeSafeMatcher<AccessibilityEvent> {
private int mType;
@@ -125,4 +139,32 @@
description.appendText("Matching to " + mDescription + " " + mProperty.toString());
}
}
+
+ public static class WindowTitleMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+ private final UiAutomation mUiAutomation;
+ private final String mTitle;
+
+ public WindowTitleMatcher(@NonNull UiAutomation uiAutomation, @NonNull String title) {
+ super();
+ mUiAutomation = uiAutomation;
+ mTitle = title;
+ }
+
+ @Override
+ protected boolean matchesSafely(AccessibilityEvent event) {
+ final List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
+ final int eventWindowId = event.getWindowId();
+ for (AccessibilityWindowInfo info : windows) {
+ if (eventWindowId == info.getId() && mTitle.equals(info.getTitle())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("With window title " + mTitle);
+ }
+ }
}
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 56badff..a576e62 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -401,6 +401,18 @@
android:resizeableActivity="true"
android:turnScreenOn="true"/>
+ <activity android:name="android.app.stubs.BubblesTestNotEmbeddableActivity"
+ android:resizeableActivity="true"
+ android:documentLaunchMode="always"
+ android:exported="true"
+ />
+
+ <activity android:name="android.app.stubs.BubblesTestNotDocumentLaunchModeActivity"
+ android:resizeableActivity="true"
+ android:allowEmbedded="true"
+ android:exported="true"
+ />
+
<service android:name="android.app.stubs.BubblesTestService"
android:label="BubblesTestsService"
android:exported="true">
diff --git a/tests/app/app/src/android/app/stubs/BubblesTestActivity.java b/tests/app/app/src/android/app/stubs/BubblesTestActivity.java
index 5a80de4..36f51c3 100644
--- a/tests/app/app/src/android/app/stubs/BubblesTestActivity.java
+++ b/tests/app/app/src/android/app/stubs/BubblesTestActivity.java
@@ -56,7 +56,7 @@
public void sendBubble(int i) {
Context context = getApplicationContext();
- final Intent intent = new Intent();
+ final Intent intent = new Intent(context, BubblesTestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setAction(Intent.ACTION_MAIN);
diff --git a/tests/app/app/src/android/app/stubs/BubblesTestNotDocumentLaunchModeActivity.java b/tests/app/app/src/android/app/stubs/BubblesTestNotDocumentLaunchModeActivity.java
new file mode 100644
index 0000000..8601ed2
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/BubblesTestNotDocumentLaunchModeActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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 android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Used by NotificationManagerTest for testing policy around bubbles.
+ */
+public class BubblesTestNotDocumentLaunchModeActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+}
diff --git a/tests/app/app/src/android/app/stubs/BubblesTestNotEmbeddableActivity.java b/tests/app/app/src/android/app/stubs/BubblesTestNotEmbeddableActivity.java
new file mode 100644
index 0000000..ced310a
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/BubblesTestNotEmbeddableActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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 android.app.stubs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Used by NotificationManagerTest for testing policy around bubbles.
+ */
+public class BubblesTestNotEmbeddableActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+}
+
diff --git a/tests/app/app/src/android/app/stubs/BubblesTestService.java b/tests/app/app/src/android/app/stubs/BubblesTestService.java
index fadf00c..6ff579b 100644
--- a/tests/app/app/src/android/app/stubs/BubblesTestService.java
+++ b/tests/app/app/src/android/app/stubs/BubblesTestService.java
@@ -59,8 +59,9 @@
}
private Notification getNotificationForTest(final int testCase, final Context context) {
+ final Intent intent = new Intent(context, BubblesTestActivity.class);
final PendingIntent pendingIntent =
- PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), 0);
+ PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
Notification.Builder nb = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
.setContentTitle("foofoo")
.setContentIntent(pendingIntent)
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 559a7bf..3513f21 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -51,6 +51,8 @@
import android.app.UiAutomation;
import android.app.stubs.AutomaticZenRuleActivity;
import android.app.stubs.BubblesTestActivity;
+import android.app.stubs.BubblesTestNotDocumentLaunchModeActivity;
+import android.app.stubs.BubblesTestNotEmbeddableActivity;
import android.app.stubs.BubblesTestService;
import android.app.stubs.R;
import android.app.stubs.TestNotificationListener;
@@ -180,6 +182,14 @@
}
}
+ private void toggleBubbleSetting(boolean enabled) throws InterruptedException {
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_BUBBLES, enabled ? 1 : 0));
+ Thread.sleep(500); // wait for ranking update
+
+ }
+
private void insertSingleContact(String name, String phone, String email, boolean starred) {
final ArrayList<ContentProviderOperation> operationList =
new ArrayList<ContentProviderOperation>();
@@ -367,7 +377,7 @@
private void sendAndVerifyBubble(final int id, Notification.Builder builder,
Notification.BubbleMetadata data, boolean shouldBeBubble) {
- final Intent intent = new Intent(Intent.ACTION_MAIN, Threads.CONTENT_URI);
+ final Intent intent = new Intent(mContext, BubblesTestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -1072,11 +1082,7 @@
}
// turn on bubbles globally
- SystemUtil.runWithShellPermissionIdentity(() ->
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_BUBBLES, 1));
-
- Thread.sleep(500); // wait for ranking update
+ toggleBubbleSetting(true);
assertEquals(1, Settings.Secure.getInt(
mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BUBBLES));
@@ -1102,25 +1108,21 @@
}
// turn off bubbles globally
- SystemUtil.runWithShellPermissionIdentity(() ->
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_BUBBLES, 0));
-
- Thread.sleep(500); // wait for ranking update
+ toggleBubbleSetting(false);
rankingMap = mListener.mRankingMap;
outRanking = new NotificationListenerService.Ranking();
for (String key : rankingMap.getOrderedKeys()) {
if (key.contains(mListener.getPackageName())) {
+ rankingMap.getRanking(key, outRanking);
assertFalse(outRanking.canBubble());
}
}
mListener.resetData();
} finally {
- SystemUtil.runWithShellPermissionIdentity(() ->
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_BUBBLES, 0));
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
}
}
@@ -2398,24 +2400,267 @@
badNumberString);
}
- public void testNotificationManagerBubblePolicy_flagForMessage_failsNoRemoteInput() {
- Person person = new Person.Builder()
- .setName("bubblebot")
- .build();
- Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
- .setContentTitle("foo")
- .setStyle(new Notification.MessagingStyle(person)
- .setConversationTitle("Bubble Chat")
- .addMessage("Hello?",
- SystemClock.currentThreadTimeMillis() - 300000, person)
- .addMessage("Is it me you're looking for?",
- SystemClock.currentThreadTimeMillis(), person)
- )
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
- sendAndVerifyBubble(1, nb, null /* use default metadata */, false);
+ public void testNotificationManagerBubblePolicy_flagForMessage_failsNoRemoteInput()
+ throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ Person person = new Person.Builder()
+ .setName("bubblebot")
+ .build();
+ Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+ .setContentTitle("foo")
+ .setStyle(new Notification.MessagingStyle(person)
+ .setConversationTitle("Bubble Chat")
+ .addMessage("Hello?",
+ SystemClock.currentThreadTimeMillis() - 300000, person)
+ .addMessage("Is it me you're looking for?",
+ SystemClock.currentThreadTimeMillis(), person)
+ )
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+ sendAndVerifyBubble(1, nb, null /* use default metadata */, false);
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
}
- public void testNotificationManagerBubblePolicy_flagForMessage_succeeds() {
+ public void testNotificationManagerBubblePolicy_flagForMessage_succeeds()
+ throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ Person person = new Person.Builder()
+ .setName("bubblebot")
+ .build();
+
+ RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel(
+ "reply").build();
+ PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
+ Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
+ inputIntent).addRemoteInput(remoteInput)
+ .build();
+
+ Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+ .setContentTitle("foo")
+ .setStyle(new Notification.MessagingStyle(person)
+ .setConversationTitle("Bubble Chat")
+ .addMessage("Hello?",
+ SystemClock.currentThreadTimeMillis() - 300000, person)
+ .addMessage("Is it me you're looking for?",
+ SystemClock.currentThreadTimeMillis(), person)
+ )
+ .setActions(replyAction)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
+ sendAndVerifyBubble(1, nb, null /* use default metadata */, shouldBeBubble);
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+ }
+
+ public void testNotificationManagerBubblePolicy_flagForPhonecall() throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
+ serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_SUCCESS);
+ mContext.startService(serviceIntent);
+
+ boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
+ if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
+ true /* shouldExist */, shouldBeBubble)) {
+ fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
+ }
+
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+ }
+
+ public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoPerson()
+ throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
+ serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_PERSON);
+ mContext.startService(serviceIntent);
+
+ if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
+ true /* shouldExist */, false /* shouldBeBubble */)) {
+ fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
+ + " or it was a bubble when it shouldn't be");
+ }
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+ }
+
+ public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoForeground()
+ throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ Person person = new Person.Builder()
+ .setName("bubblebot")
+ .build();
+ Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+ .setContentTitle("foo")
+ .setCategory(CATEGORY_CALL)
+ .addPerson(person)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+ sendAndVerifyBubble(1, nb, null /* use default metadata */, false /* shouldBeBubble */);
+
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+ }
+
+ public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoCategory()
+ throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
+ serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_CATEGORY);
+ mContext.startService(serviceIntent);
+
+ if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
+ true /* shouldExist */, false /* shouldBeBubble */)) {
+ fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
+ + " or it was a bubble when it shouldn't be");
+ }
+
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+
+ }
+
+ public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoMetadata()
+ throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
+ serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_BUBBLE_METADATA);
+ mContext.startService(serviceIntent);
+
+ if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
+ true /* shouldExist */, false /* shouldBeBubble */)) {
+ fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
+ + " or it was a bubble when it shouldn't be");
+ }
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+ }
+
+ public void testNotificationManagerBubblePolicy_noFlagForAppNotForeground()
+ throws InterruptedException {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ sendAndVerifyBubble(1, null /* use default notif */, null /* use default metadata */,
+ false /* shouldBeBubble */);
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+ }
+
+ public void testNotificationManagerBubblePolicy_flagForAppForeground() throws Exception {
+ try {
+ // turn on bubbles globally
+ toggleBubbleSetting(true);
+
+ final CountDownLatch latch = new CountDownLatch(2);
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ latch.countDown();
+ }
+ };
+ IntentFilter filter = new IntentFilter(BubblesTestActivity.BUBBLE_ACTIVITY_OPENED);
+ mContext.registerReceiver(receiver, filter);
+
+ // Start & get the activity
+ BubblesTestActivity a = (BubblesTestActivity) launchSendBubbleActivity();
+
+ // Make sure device is unlocked
+ KeyguardManager keyguardManager =
+ (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ keyguardManager.requestDismissKeyguard(a, new KeyguardManager.KeyguardDismissCallback() {
+ @Override
+ public void onDismissSucceeded() {
+ latch.countDown();
+ }
+ });
+ try {
+ latch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ // Should be foreground now
+ a.sendBubble(1);
+
+ if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
+ true /* shouldExist */, true /* shouldBeBubble */)) {
+ fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
+ }
+
+ // Make ourselves not foreground
+ HomeHelper homeHelper = new HomeHelper();
+ homeHelper.goHome();
+
+ // The notif should be allowed to update as a bubble
+ a.sendBubble(2);
+
+ boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
+
+ if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
+ true /* shouldExist */, shouldBeBubble)) {
+ fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
+ }
+
+ // Cancel the notif
+ cancelAndPoll(BUBBLE_NOTIF_ID);
+
+ // Send it again when not foreground, this should not be a bubble & just be a notif
+ a.sendBubble(3);
+ if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
+ true /* shouldExist */, false /* shouldBeBubble */)) {
+ fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
+ + " or it was a bubble when it shouldn't be");
+ }
+
+ mContext.unregisterReceiver(receiver);
+ homeHelper.close();
+ } finally {
+ // turn off bubbles globally
+ toggleBubbleSetting(false);
+ }
+ }
+
+ public void testNotificationManagerBubblePolicy_noFlag_notEmbeddable() throws Exception {
Person person = new Person.Builder()
.setName("bubblebot")
.build();
@@ -2439,138 +2684,51 @@
.setActions(replyAction)
.setSmallIcon(android.R.drawable.sym_def_app_icon);
- boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
- sendAndVerifyBubble(1, nb, null /* use default metadata */, shouldBeBubble);
+ final Intent intent = new Intent(mContext, BubblesTestNotEmbeddableActivity.class);
+ final PendingIntent pendingIntent =
+ PendingIntent.getActivity(mContext, 0, intent, 0);
+
+ Notification.BubbleMetadata.Builder metadataBuilder =
+ new Notification.BubbleMetadata.Builder()
+ .setIntent(pendingIntent)
+ .setIcon(Icon.createWithResource(mContext, R.drawable.black));
+
+ sendAndVerifyBubble(1, nb, metadataBuilder.build(), false);
}
- public void testNotificationManagerBubblePolicy_flagForPhonecall() {
- Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
- serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_SUCCESS);
- mContext.startService(serviceIntent);
-
- boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, shouldBeBubble)) {
- fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
- }
- }
-
- public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoPerson() {
- Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
- serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_PERSON);
- mContext.startService(serviceIntent);
-
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
- + " or it was a bubble when it shouldn't be");
- }
- }
-
- public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoForeground() {
+ public void testNotificationManagerBubblePolicy_noFlag_notDocumentLaunchModeAlways() throws Exception {
Person person = new Person.Builder()
.setName("bubblebot")
.build();
+
+ RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
+ PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
+ Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
+ inputIntent).addRemoteInput(remoteInput)
+ .build();
+
Notification.Builder nb = new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.setContentTitle("foo")
- .setCategory(CATEGORY_CALL)
- .addPerson(person)
+ .setStyle(new Notification.MessagingStyle(person)
+ .setConversationTitle("Bubble Chat")
+ .addMessage("Hello?",
+ SystemClock.currentThreadTimeMillis() - 300000, person)
+ .addMessage("Is it me you're looking for?",
+ SystemClock.currentThreadTimeMillis(), person)
+ )
+ .setActions(replyAction)
.setSmallIcon(android.R.drawable.sym_def_app_icon);
- sendAndVerifyBubble(1, nb, null /* use default metadata */, false /* shouldBeBubble */);
- }
- public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoCategory() {
- Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
- serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_CATEGORY);
- mContext.startService(serviceIntent);
+ final Intent intent = new Intent(mContext, BubblesTestNotDocumentLaunchModeActivity.class);
+ final PendingIntent pendingIntent =
+ PendingIntent.getActivity(mContext, 0, intent, 0);
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
- + " or it was a bubble when it shouldn't be");
- }
- }
+ Notification.BubbleMetadata.Builder metadataBuilder =
+ new Notification.BubbleMetadata.Builder()
+ .setIntent(pendingIntent)
+ .setIcon(Icon.createWithResource(mContext, R.drawable.black));
- public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoMetadata() {
- Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
- serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_BUBBLE_METADATA);
- mContext.startService(serviceIntent);
-
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
- + " or it was a bubble when it shouldn't be");
- }
- }
-
- public void testNotificationManagerBubblePolicy_noFlagForAppNotForeground() {
- sendAndVerifyBubble(1, null /* use default notif */, null /* use default metadata */,
- false /* shouldBeBubble */);
- }
-
- public void testNotificationManagerBubblePolicy_flagForAppForeground() throws Exception {
- final CountDownLatch latch = new CountDownLatch(2);
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- latch.countDown();
- }
- };
- IntentFilter filter = new IntentFilter(BubblesTestActivity.BUBBLE_ACTIVITY_OPENED);
- mContext.registerReceiver(receiver, filter);
-
- // Start & get the activity
- BubblesTestActivity a = (BubblesTestActivity) launchSendBubbleActivity();
-
- // Make sure device is unlocked
- KeyguardManager keyguardManager =
- (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- keyguardManager.requestDismissKeyguard(a, new KeyguardManager.KeyguardDismissCallback() {
- @Override
- public void onDismissSucceeded() {
- latch.countDown();
- }
- });
- try {
- latch.await(100, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- // Should be foreground now
- a.sendBubble(1);
-
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, true /* shouldBeBubble */)) {
- fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
- }
-
- // Make ourselves not foreground
- HomeHelper homeHelper = new HomeHelper();
- homeHelper.goHome();
-
- // The notif should be allowed to update as a bubble
- a.sendBubble(2);
-
- boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
-
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, shouldBeBubble)) {
- fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
- }
-
- // Cancel the notif
- cancelAndPoll(BUBBLE_NOTIF_ID);
-
- // Send it again when not foreground, this should not be a bubble & just be a notif
- a.sendBubble(3);
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
- + " or it was a bubble when it shouldn't be");
- }
-
- mContext.unregisterReceiver(receiver);
- homeHelper.close();
+ sendAndVerifyBubble(1, nb, metadataBuilder.build(), false);
}
}
diff --git a/tests/attentionservice/src/android/attentionservice/cts/CtsAttentionServiceDeviceTest.java b/tests/attentionservice/src/android/attentionservice/cts/CtsAttentionServiceDeviceTest.java
index 5e41cf4..45a7247 100644
--- a/tests/attentionservice/src/android/attentionservice/cts/CtsAttentionServiceDeviceTest.java
+++ b/tests/attentionservice/src/android/attentionservice/cts/CtsAttentionServiceDeviceTest.java
@@ -21,9 +21,12 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeTrue;
+
import android.platform.test.annotations.AppModeFull;
import android.provider.DeviceConfig;
import android.service.attention.AttentionService;
+import android.text.TextUtils;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -45,6 +48,8 @@
private static final String SERVICE_ENABLED = "service_enabled";
private static final String FAKE_SERVICE_PACKAGE =
CtsTestAttentionService.class.getPackage().getName();
+ private final boolean isTestable =
+ !TextUtils.isEmpty(getAttentionServiceComponent());
@Rule
public final DeviceConfigStateChangerRule mLookAllTheseRules =
@@ -55,6 +60,7 @@
@Before
public void setUp() {
+ assumeTrue("Feature not available on this device. Skipping test.", isTestable);
clearTestableAttentionService();
CtsTestAttentionService.reset();
bindToTestService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 3413422..31fd320 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -1414,6 +1414,21 @@
}
/**
+ * Asserts {@link View#isAutofilled()} state of the given view, waiting if necessarity to avoid
+ * race conditions.
+ */
+ public static void assertViewAutofillState(@NonNull View view, boolean expected)
+ throws Exception {
+ Timeouts.FILL_TIMEOUT.run("assertViewAutofillState(" + view + ", " + expected + ")",
+ () -> {
+ final boolean actual = view.isAutofilled();
+ Log.v(TAG, "assertViewAutofillState(): expected=" + expected + ", actual="
+ + actual);
+ return actual == expected ? "not_used" : null;
+ });
+ }
+
+ /**
* Allows the test to draw overlaid windows.
*
* <p>Should call {@link #disallowOverlays()} afterwards.
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index e4d77bc..b7241b3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -32,6 +32,7 @@
import static android.autofillservice.cts.Helper.assertTextIsSanitized;
import static android.autofillservice.cts.Helper.assertTextOnly;
import static android.autofillservice.cts.Helper.assertValue;
+import static android.autofillservice.cts.Helper.assertViewAutofillState;
import static android.autofillservice.cts.Helper.disallowOverlays;
import static android.autofillservice.cts.Helper.dumpStructure;
import static android.autofillservice.cts.Helper.findAutofillIdByResourceId;
@@ -985,6 +986,7 @@
// Check the results.
mActivity.assertAutoFilled();
+ assertViewAutofillState(mActivity.getPassword(), true);
// Try to login, it will fail.
final String loginMessage = mActivity.tapLogin();
@@ -993,6 +995,7 @@
// Set right password...
mActivity.onPassword((v) -> v.setText("dude"));
+ assertViewAutofillState(mActivity.getPassword(), false);
// ... and try again
final String expectedMessage = getWelcomeMessage("dude");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 40a9589..2e56a02 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -1024,6 +1024,7 @@
try {
file = Helper.createTestFile("screenshot.png");
if (file != null) {
+ Log.i(TAG, "Taking screenshot on " + file);
final Bitmap screenshot = takeScreenshot();
Helper.dumpBitmap(screenshot, file);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
index dea07e3..64c2d78 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
@@ -21,6 +21,7 @@
import static android.autofillservice.cts.Helper.ID_USERNAME;
import static android.autofillservice.cts.Helper.assertHasFlags;
import static android.autofillservice.cts.Helper.assertTextAndValue;
+import static android.autofillservice.cts.Helper.assertViewAutofillState;
import static android.autofillservice.cts.Helper.findNodeByResourceId;
import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
import static android.autofillservice.cts.UiBot.LANDSCAPE;
@@ -349,6 +350,72 @@
@Test
@AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
+ public void testCancellationSignalCalled_retriggerAugmentedAutofill() throws Exception {
+ // Set services
+ enableService();
+ enableAugmentedService();
+
+ // Set expectations
+ final EditText username = mActivity.getUsername();
+ final AutofillId usernameId = username.getAutofillId();
+ final AutofillValue expectedFocusedValue = username.getAutofillValue();
+ sReplier.addResponse(NO_RESPONSE);
+ sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
+ .setDataset(new CannedAugmentedFillResponse.Dataset.Builder("Augment Me")
+ .setField(usernameId, "dude")
+ .setField(mActivity.getPassword().getAutofillId(), "sweet")
+ .build(), usernameId)
+ .build());
+
+ final OneTimeCancellationSignalListener listener =
+ new OneTimeCancellationSignalListener(AUGMENTED_FILL_TIMEOUT.ms() + 5000);
+
+ // Trigger autofill
+ mActivity.onUsername(View::requestFocus);
+ sReplier.getNextFillRequest();
+ final AugmentedFillRequest request = sAugmentedReplier.getNextFillRequest();
+
+ // Assert request
+ assertBasicRequestInfo(request, mActivity, usernameId, expectedFocusedValue);
+ mAugmentedUiBot.assertUiShown(usernameId, "Augment Me");
+
+ final CancellationSignal cancellationSignal = request.cancellationSignal;
+
+ assertThat(cancellationSignal).isNotNull();
+ cancellationSignal.setOnCancelListener(listener);
+
+ // Move focus away to make sure Augmented Autofill UI is gone.
+ mActivity.clearFocus();
+ mAugmentedUiBot.assertUiGone();
+
+ // Set expectations for username again.
+ sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
+ .setDataset(new CannedAugmentedFillResponse.Dataset.Builder("Augment Me")
+ .setField(usernameId, "dude")
+ .setField(mActivity.getPassword().getAutofillId(), "sweet")
+ .build(), usernameId)
+ .build());
+
+ // Tap on username again
+ mActivity.onUsername(View::requestFocus);
+ final AugmentedFillRequest request2 = sAugmentedReplier.getNextFillRequest();
+
+ // Assert first request cancelled
+ listener.assertOnCancelCalled();
+
+ // Assert request
+ assertBasicRequestInfo(request2, mActivity, usernameId, expectedFocusedValue);
+ final UiObject2 ui = mAugmentedUiBot.assertUiShown(usernameId, "Augment Me");
+
+ // ...and autofill this time
+ mActivity.expectAutoFill("dude", "sweet");
+ ui.click();
+ mActivity.assertAutoFilled();
+ mAugmentedUiBot.assertUiGone();
+ }
+
+ @Test
+ @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
public void testAugmentedAutoFill_multipleRequests() throws Exception {
// Set services
enableService();
@@ -418,6 +485,50 @@
}
@Test
+ @AppModeFull(reason = "testAutoFill_mainServiceReturnedNull_augmentedAutofillOneField enough")
+ public void testAugmentedAutoFill_thenEditField() throws Exception {
+ // Set services
+ enableService();
+ enableAugmentedService();
+
+ // Set expectations
+ final EditText username = mActivity.getUsername();
+ final AutofillId usernameId = username.getAutofillId();
+ final AutofillValue expectedFocusedValue = username.getAutofillValue();
+ sReplier.addResponse(NO_RESPONSE);
+ sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
+ .setDataset(new CannedAugmentedFillResponse.Dataset.Builder("Augment Me")
+ .setField(usernameId, "dude")
+ .build(), usernameId)
+ .build());
+ mActivity.expectAutoFill("dude");
+
+ // Trigger autofill
+ mActivity.onUsername(View::requestFocus);
+ sReplier.getNextFillRequest();
+ final AugmentedFillRequest request = sAugmentedReplier.getNextFillRequest();
+
+ // Assert request
+ assertBasicRequestInfo(request, mActivity, usernameId, expectedFocusedValue);
+
+ // Make sure standard Autofill UI is not shown.
+ mUiBot.assertNoDatasetsEver();
+
+ // Make sure Augmented Autofill UI is shown.
+ final UiObject2 ui = mAugmentedUiBot.assertUiShown(usernameId, "Augment Me");
+
+ // Autofill
+ ui.click();
+ mActivity.assertAutoFilled();
+ mAugmentedUiBot.assertUiGone();
+ assertViewAutofillState(mActivity.getUsername(), true);
+
+ // Now change value and make sure autofill status is changed
+ mActivity.onUsername((v) -> v.setText("I AM GROOT"));
+ assertViewAutofillState(mActivity.getUsername(), false);
+ }
+
+ @Test
public void testAugmentedAutoFill_callback() throws Exception {
// Set services
enableService();
diff --git a/tests/camera/src/android/hardware/camera2/cts/HeifWriterTest.java b/tests/camera/src/android/hardware/camera2/cts/HeifWriterTest.java
index 060c022..0cb5c1b 100644
--- a/tests/camera/src/android/hardware/camera2/cts/HeifWriterTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/HeifWriterTest.java
@@ -66,7 +66,12 @@
@Override
public void setUp() throws Exception {
super.setUp();
- mFilePath = mContext.getExternalFilesDir(null).getPath();
+
+ File filesDir = mContext.getPackageManager().isInstantApp()
+ ? mContext.getFilesDir()
+ : mContext.getExternalFilesDir(null);
+
+ mFilePath = filesDir.getPath();
}
@Override
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index 2ceda1e..b7510e6 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -1377,12 +1377,14 @@
Log.i(TAG, String.format(
"Testing Camera %s for abandoning surface of a repeating request", id));
- openDevice(id);
- if (!mStaticInfo.isColorOutputSupported()) {
+ StaticMetadata staticInfo = mAllStaticInfo.get(id);
+ if (!staticInfo.isColorOutputSupported()) {
Log.i(TAG, "Camera " + id + " does not support color output, skipping");
continue;
}
+ openDevice(id);
+
try {
SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
index 80d570b..4cd0046 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
@@ -48,6 +48,7 @@
import com.android.ex.camera2.blocking.BlockingSessionCallback;
import com.android.ex.camera2.blocking.BlockingStateCallback;
+import java.io.File;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -115,7 +116,12 @@
mHandler = new Handler(mHandlerThread.getLooper());
mCameraListener = new BlockingStateCallback();
mCollector = new CameraErrorCollector();
- mDebugFileNameBase = getContext().getExternalFilesDir(null).getPath();
+
+ File filesDir = mContext.getPackageManager().isInstantApp()
+ ? mContext.getFilesDir()
+ : mContext.getExternalFilesDir(null);
+
+ mDebugFileNameBase = filesDir.getPath();
mAllStaticInfo = new HashMap<String, StaticMetadata>();
List<String> hiddenPhysicalIds = new ArrayList<>();
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index b2b7828..1f8b792 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -59,6 +59,7 @@
import org.junit.Before;
import org.junit.Rule;
+import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -135,7 +136,12 @@
mHandler = new Handler(mHandlerThread.getLooper());
mCameraListener = new BlockingStateCallback();
mCollector = new CameraErrorCollector();
- mDebugFileNameBase = mContext.getExternalFilesDir(null).getPath();
+
+ File filesDir = mContext.getPackageManager().isInstantApp()
+ ? mContext.getFilesDir()
+ : mContext.getExternalFilesDir(null);
+
+ mDebugFileNameBase = filesDir.getPath();
mAllStaticInfo = new HashMap<String, StaticMetadata>();
List<String> hiddenPhysicalIds = new ArrayList<>();
diff --git a/tests/camera/src/android/hardware/cts/CameraTest.java b/tests/camera/src/android/hardware/cts/CameraTest.java
index 51605f0..b6fe28a 100644
--- a/tests/camera/src/android/hardware/cts/CameraTest.java
+++ b/tests/camera/src/android/hardware/cts/CameraTest.java
@@ -150,6 +150,7 @@
*/
private void initializeMessageLooper(final int cameraId) throws IOException {
final ConditionVariable startDone = new ConditionVariable();
+ final CameraCtsActivity activity = mActivityRule.getActivity();
new Thread() {
@Override
public void run() {
@@ -161,7 +162,7 @@
mLooper = Looper.myLooper();
try {
mIsExternalCamera = CameraUtils.isExternal(
- mActivityRule.getActivity().getApplicationContext(), cameraId);
+ activity.getApplicationContext(), cameraId);
} catch (Exception e) {
Log.e(TAG, "Unable to query external camera!" + e);
}
@@ -185,8 +186,13 @@
fail("initializeMessageLooper: start timeout");
}
assertNotNull("Fail to open camera.", mCamera);
- mCamera.setPreviewDisplay(mActivityRule.getActivity().getSurfaceView().getHolder());
- mJpegPath = mActivityRule.getActivity().getExternalFilesDir(null).getPath() + "/test.jpg";
+ mCamera.setPreviewDisplay(activity.getSurfaceView().getHolder());
+
+ File parent = activity.getPackageManager().isInstantApp()
+ ? activity.getFilesDir()
+ : activity.getExternalFilesDir(null);
+
+ mJpegPath = parent.getPath() + "/test.jpg";
}
/*
diff --git a/tests/camera/src/android/hardware/multiprocess/camera/cts/MediaRecorderCameraActivity.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/MediaRecorderCameraActivity.java
index 1f12cea..186706b 100644
--- a/tests/camera/src/android/hardware/multiprocess/camera/cts/MediaRecorderCameraActivity.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/MediaRecorderCameraActivity.java
@@ -58,7 +58,12 @@
mErrorServiceConnection.start();
mMediaRecorder = new MediaRecorder();
- mOutputPath = new File(getExternalFilesDir(null), "record.out").getAbsolutePath();
+
+ File filesDir = getPackageManager().isInstantApp()
+ ? getFilesDir()
+ : getExternalFilesDir(null);
+
+ mOutputPath = new File(filesDir, "record.out").getAbsolutePath();
}
@Override
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 3ed4cfe..77fa6dd 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -61,6 +61,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -178,6 +179,7 @@
APP_A_FOREGROUND_ACTIVITY);
}
+ @Ignore // test temporarily disabled due to bg activity start grace period introduction
@Test
public void testActivityNotBlockedwhenForegroundActivityLaunchInSameTask() throws Exception {
// Start foreground activity, and foreground activity able to launch background activity
@@ -208,6 +210,7 @@
APP_A_FOREGROUND_ACTIVITY);
}
+ @Ignore // test temporarily disabled due to bg activity start grace period introduction
@Test
public void testActivityNotBlockedWhenForegroundActivityLaunchInDifferentTask()
throws Exception {
@@ -240,6 +243,7 @@
assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
}
+ @Ignore // test temporarily disabled due to bg activity start grace period introduction
@Test
@FlakyTest(bugId = 130800326)
public void testActivityBlockedWhenForegroundActivityRestartsItself() throws Exception {
diff --git a/tests/tests/content/AndroidTest.xml b/tests/tests/content/AndroidTest.xml
index 4228c26..418c201 100644
--- a/tests/tests/content/AndroidTest.xml
+++ b/tests/tests/content/AndroidTest.xml
@@ -40,7 +40,6 @@
<option name="test-file-name" value="CtsContentTestCases.apk" />
<option name="test-file-name" value="CtsContentDirectBootUnawareTestApp.apk" />
<option name="test-file-name" value="CtsContentPartiallyDirectBootAwareTestApp.apk" />
- <option name="test-file-name" value="CtsContentDirectBootAwareTestApp.apk" />
<option name="test-file-name" value="CtsSyncAccountAccessStubs.apk" />
<option name="test-file-name" value="CtsBinderPermissionTestService.apk" />
</target_preparer>
diff --git a/tests/tests/content/DirectBootAwareTestApp/Android.bp b/tests/tests/content/DirectBootAwareTestApp/Android.bp
deleted file mode 100644
index 17ccda1..0000000
--- a/tests/tests/content/DirectBootAwareTestApp/Android.bp
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (C) 2019 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.
-
-android_test_helper_app {
- name: "CtsContentDirectBootAwareTestApp",
- defaults: ["cts_defaults"],
- sdk_version: "current",
- // tag this module as a cts test artifact
- test_suites: [
- "cts",
- "vts",
- "general-tests",
- ],
-}
diff --git a/tests/tests/content/DirectBootAwareTestApp/AndroidManifest.xml b/tests/tests/content/DirectBootAwareTestApp/AndroidManifest.xml
deleted file mode 100644
index b4753b9..0000000
--- a/tests/tests/content/DirectBootAwareTestApp/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2019 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.
- -->
-
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.content.cts.directbootaware">
-
- <application
- android:directBootAware="true"
- android:hasCode="false"
- android:label="Direct Boot Aware Test App" />
-</manifest>
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index 728bcbe..7260c3c 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -57,8 +57,6 @@
"android.content.cts.directbootunaware";
private static final String PARTIALLY_DIRECT_BOOT_AWARE_PACKAGE_NAME =
"android.content.cts.partiallydirectbootaware";
- private static final String DIRECT_BOOT_AWARE_PACKAGE_NAME =
- "android.content.cts.directbootaware";
private ApplicationInfo mApplicationInfo;
private String mPackageName;
@@ -217,11 +215,4 @@
PARTIALLY_DIRECT_BOOT_AWARE_PACKAGE_NAME, 0);
assertTrue(applicationInfo.isEncryptionAware());
}
-
- @Test
- public void testDirectBootAwareAppIsEncryptionAware() throws Exception {
- ApplicationInfo applicationInfo = getContext().getPackageManager().getApplicationInfo(
- DIRECT_BOOT_AWARE_PACKAGE_NAME, 0);
- assertTrue(applicationInfo.isEncryptionAware());
- }
}
diff --git a/tests/tests/gesture/AndroidTest.xml b/tests/tests/gesture/AndroidTest.xml
index 10d1e6a..0c1c200 100644
--- a/tests/tests/gesture/AndroidTest.xml
+++ b/tests/tests/gesture/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsGestureTestCases.apk" />
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
index 91a6acf..f01665a 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
@@ -183,6 +183,12 @@
playVideoWithRetries(uri, headers, cookies, null /* width */, null /* height */, playTime);
}
+ protected void playLiveAudioOnlyTest(
+ Uri uri, Map<String, String> headers, List<HttpCookie> cookies,
+ int playTime) throws Exception {
+ playVideoWithRetries(uri, headers, cookies, -1 /* width */, -1 /* height */, playTime);
+ }
+
protected void playVideoWithRetries(
Uri uri, Map<String, String> headers, List<HttpCookie> cookies,
Integer width, Integer height, int playTime) throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 8f63a75..789d1ba 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -187,7 +187,7 @@
// Play stream for 60 seconds
// limit rate to workaround multiplication overflow in framework
- localHlsTest("hls_variant/index.m3u8", 60 * 1000, LOCAL_HLS_BITS_PER_MS);
+ localHlsTest("hls_variant/index.m3u8", 60 * 1000, LOCAL_HLS_BITS_PER_MS, false /*isAudioOnly*/);
}
public void testHlsWithHeadersCookies() throws Exception {
@@ -215,7 +215,7 @@
// Play stream for 60 seconds
// limit rate to workaround multiplication overflow in framework
- localHlsTest("hls_variant/index.m3u8", 60 * 1000, LOCAL_HLS_BITS_PER_MS);
+ localHlsTest("hls_variant/index.m3u8", 60 * 1000, LOCAL_HLS_BITS_PER_MS, false /*isAudioOnly*/);
}
public void testHlsSampleAes_bbb_audio_only_overridable() throws Exception {
@@ -228,7 +228,7 @@
// if url override provided
playLiveAudioOnlyTest(mInputUrl, 60 * 1000);
} else {
- localHlsTest("audio_only/index.m3u8", 60 * 1000, -1);
+ localHlsTest("audio_only/index.m3u8", 60 * 1000, -1, true /*isAudioOnly*/);
}
}
@@ -239,7 +239,7 @@
}
// Play stream for 60 seconds
- localHlsTest("unmuxed_1500k/index.m3u8", 60 * 1000, -1);
+ localHlsTest("unmuxed_1500k/index.m3u8", 60 * 1000, -1, false /*isAudioOnly*/);
}
@@ -379,21 +379,21 @@
if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
return; // skip
}
- localHlsTest("hls.m3u8", false, false);
+ localHlsTest("hls.m3u8", false, false, false /*isAudioOnly*/);
}
public void testPlayHlsStreamWithQueryString() throws Throwable {
if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
return; // skip
}
- localHlsTest("hls.m3u8", true, false);
+ localHlsTest("hls.m3u8", true, false, false /*isAudioOnly*/);
}
public void testPlayHlsStreamWithRedirect() throws Throwable {
if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
return; // skip
}
- localHlsTest("hls.m3u8", false, true);
+ localHlsTest("hls.m3u8", false, true, false /*isAudioOnly*/);
}
public void testPlayHlsStreamWithTimedId3() throws Throwable {
@@ -576,19 +576,19 @@
worker.quit();
}
- private void localHlsTest(final String name, boolean appendQueryString, boolean redirect)
- throws Exception {
- localHlsTest(name, null, null, appendQueryString, redirect, 10, -1);
+ private void localHlsTest(final String name, boolean appendQueryString,
+ boolean redirect, boolean isAudioOnly) throws Exception {
+ localHlsTest(name, null, null, appendQueryString, redirect, 10, -1, isAudioOnly);
}
- private void localHlsTest(final String name, int playTime, int bitsPerMs)
+ private void localHlsTest(final String name, int playTime, int bitsPerMs, boolean isAudioOnly)
throws Exception {
- localHlsTest(name, null, null, false, false, playTime, bitsPerMs);
+ localHlsTest(name, null, null, false, false, playTime, bitsPerMs, isAudioOnly);
}
private void localHlsTest(String name, Map<String, String> headers, List<HttpCookie> cookies,
- boolean appendQueryString, boolean redirect, int playTime, int bitsPerMs)
- throws Exception {
+ boolean appendQueryString, boolean redirect, int playTime, int bitsPerMs,
+ boolean isAudioOnly) throws Exception {
if (bitsPerMs >= 0) {
mServer = new CtsTestServer(mContext) {
@Override
@@ -609,8 +609,11 @@
if (appendQueryString) {
stream_url += "?foo=bar/baz";
}
-
- playLiveVideoTest(Uri.parse(stream_url), headers, cookies, playTime);
+ if (isAudioOnly) {
+ playLiveAudioOnlyTest(Uri.parse(stream_url), headers, cookies, playTime);
+ } else {
+ playLiveVideoTest(Uri.parse(stream_url), headers, cookies, playTime);
+ }
} finally {
mServer.shutdown();
}
diff --git a/tests/tests/os/assets/minijail/isolated-common.policy b/tests/tests/os/assets/minijail/isolated-common.policy
index a8f4e25..11205ae 100644
--- a/tests/tests/os/assets/minijail/isolated-common.policy
+++ b/tests/tests/os/assets/minijail/isolated-common.policy
@@ -75,6 +75,7 @@
# madvise: advice==MADV_DONTNEED
madvise: arg2 == 4; return EPERM
+membarrier: 1
memfd_create: return EPERM
mkdirat: return EPERM
mknodat: return EPERM
diff --git a/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt b/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
index e99476a..10c2efa 100644
--- a/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
+++ b/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
@@ -183,9 +183,4 @@
fun uninstallTestPackage() {
uiDevice.executeShellCommand("pm uninstall $TEST_APK_PACKAGE_NAME")
}
-
- @After
- fun resetAppOps() {
- AppOpsUtils.reset(packageName)
- }
}
diff --git a/tests/tests/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java b/tests/tests/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java
index 227ef5b..32e4296 100644
--- a/tests/tests/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java
+++ b/tests/tests/permission/telephony/src/android/permission/cts/telephony/TelephonyManagerPermissionTest.java
@@ -275,6 +275,30 @@
}
}
+ /**
+ * Verify that getNetworkType and getDataNetworkType requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ */
+ @Test
+ public void testGetNetworkType() {
+ if (!mHasTelephony) {
+ return;
+ }
+
+ if (mTelephonyManager.getNetworkType() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+ fail("getNetworkType should return UNKNOWN");
+ }
+
+ try {
+ mTelephonyManager.getDataNetworkType();
+ fail("getDataNetworkType did not throw a SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
private static Context getContext() {
return InstrumentationRegistry.getContext();
}
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
index 031aa65..586c74c 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
@@ -16,16 +16,18 @@
package android.permission2.cts;
+import static android.permission2.cts.Utils.eventually;
+
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
-import static org.junit.Assert.fail;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
import android.Manifest;
import android.Manifest.permission;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
-
-
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
@@ -34,18 +36,19 @@
import android.platform.test.annotations.AppModeFull;
import android.util.ArraySet;
-import java.util.Collections;
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.util.Collections;
import java.util.Set;
import javax.annotation.Nullable;
-import androidx.annotation.NonNull;
-import androidx.test.platform.app.InstrumentationRegistry;
-
/**
* Tests for restricted permission behaviors.
*/
@@ -69,19 +72,6 @@
private static @NonNull BroadcastReceiver sCommandReceiver;
- public interface ThrowingRunnable extends Runnable {
- void runOrThrow() throws Exception;
-
- @Override
- default void run() {
- try {
- runOrThrow();
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
- }
-
@BeforeClass
public static void setUpOnce() {
sCommandReceiver = new CommandBroadcastReceiver();
@@ -99,81 +89,65 @@
@Test
@AppModeFull
public void testDefaultAllRestrictedPermissionsWhitelistedAtInstall() throws Exception {
- try {
- // Install with no changes to whitelisted permissions, not attempting to grant.
- installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
- null /*grantedPermissions*/);
+ // Install with no changes to whitelisted permissions, not attempting to grant.
+ installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
+ null /*grantedPermissions*/);
- // All restricted permission should be whitelisted.
- assertAllRestrictedPermissionWhitelisted();
+ // All restricted permission should be whitelisted.
+ assertAllRestrictedPermissionWhitelisted();
- // No restricted permission should be granted.
- assertNoRestrictedPermissionGranted();
- } finally {
- uninstallApp();
- }
+ // No restricted permission should be granted.
+ assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testSomeRestrictedPermissionsWhitelistedAtInstall() throws Exception {
- try {
- // Whitelist only these permissions.
- final Set<String> whitelistedPermissions = new ArraySet<>(2);
- whitelistedPermissions.add(Manifest.permission.SEND_SMS);
- whitelistedPermissions.add(Manifest.permission.READ_CALL_LOG);
+ // Whitelist only these permissions.
+ final Set<String> whitelistedPermissions = new ArraySet<>(2);
+ whitelistedPermissions.add(Manifest.permission.SEND_SMS);
+ whitelistedPermissions.add(Manifest.permission.READ_CALL_LOG);
- // Install with some whitelisted permissions, not attempting to grant.
- installRestrictedPermissionUserApp(whitelistedPermissions, null /*grantedPermissions*/);
+ // Install with some whitelisted permissions, not attempting to grant.
+ installRestrictedPermissionUserApp(whitelistedPermissions, null /*grantedPermissions*/);
- // Some restricted permission should be whitelisted.
- assertRestrictedPermissionWhitelisted(whitelistedPermissions);
+ // Some restricted permission should be whitelisted.
+ eventually(() -> assertRestrictedPermissionWhitelisted(whitelistedPermissions));
- // No restricted permission should be granted.
- assertNoRestrictedPermissionGranted();
- } finally {
- uninstallApp();
- }
+ // No restricted permission should be granted.
+ assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testNoneRestrictedPermissionWhitelistedAtInstall() throws Exception {
- try {
- // Install with all whitelisted permissions, not attempting to grant.
- installRestrictedPermissionUserApp(Collections.emptySet(),
- null /*grantedPermissions*/);
+ // Install with all whitelisted permissions, not attempting to grant.
+ installRestrictedPermissionUserApp(Collections.emptySet(),
+ null /*grantedPermissions*/);
- // No restricted permission should be whitelisted.
- assertNoRestrictedPermissionWhitelisted();
+ // No restricted permission should be whitelisted.
+ assertNoRestrictedPermissionWhitelisted();
- // No restricted permission should be granted.
- assertNoRestrictedPermissionGranted();
- } finally {
- uninstallApp();
- }
+ // No restricted permission should be granted.
+ assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testSomeRestrictedPermissionsGrantedAtInstall() throws Exception {
- try {
- // Grant only these permissions.
- final Set<String> grantedPermissions = new ArraySet<>(1);
- grantedPermissions.add(Manifest.permission.SEND_SMS);
- grantedPermissions.add(Manifest.permission.READ_CALL_LOG);
+ // Grant only these permissions.
+ final Set<String> grantedPermissions = new ArraySet<>(1);
+ grantedPermissions.add(Manifest.permission.SEND_SMS);
+ grantedPermissions.add(Manifest.permission.READ_CALL_LOG);
- // Install with no whitelisted permissions attempting to grant.
- installRestrictedPermissionUserApp(null /*whitelistedPermissions*/, grantedPermissions);
+ // Install with no whitelisted permissions attempting to grant.
+ installRestrictedPermissionUserApp(null /*whitelistedPermissions*/, grantedPermissions);
- // All restricted permission should be whitelisted.
- assertAllRestrictedPermissionWhitelisted();
+ // All restricted permission should be whitelisted.
+ assertAllRestrictedPermissionWhitelisted();
- // Some restricted permission should be granted.
- assertRestrictedPermissionGranted(grantedPermissions);
- } finally {
- uninstallApp();
- }
+ // Some restricted permission should be granted.
+ assertRestrictedPermissionGranted(grantedPermissions);
}
@Test
@@ -195,206 +169,204 @@
@Test
@AppModeFull
public void testAllRestrictedPermissionsGrantedAtInstall() throws Exception {
- try {
- // Install with whitelisted permissions attempting to grant.
- installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
- Collections.emptySet());
+ // Install with whitelisted permissions attempting to grant.
+ installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
+ Collections.emptySet());
- // All restricted permission should be whitelisted.
- assertAllRestrictedPermissionWhitelisted();
+ // All restricted permission should be whitelisted.
+ assertAllRestrictedPermissionWhitelisted();
- // Some restricted permission should be granted.
- assertAllRestrictedPermissionGranted();
- } finally {
- uninstallApp();
- }
+ // Some restricted permission should be granted.
+ assertAllRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testWhitelistAccessControl() throws Exception {
- try {
- // Install with no whitelisted permissions not attempting to grant.
- installRestrictedPermissionUserApp(Collections.emptySet(),
- Collections.emptySet());
+ // Install with no whitelisted permissions not attempting to grant.
+ installRestrictedPermissionUserApp(Collections.emptySet(),
+ Collections.emptySet());
- assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
- PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
+ assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
- assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
- PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
+ assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
- assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
- PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
- } finally {
- uninstallApp();
- }
+ assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
}
@Test
@AppModeFull
public void testStorageTargetingSdk28DefaultWhitelistedHasFullAccess() throws Exception {
- try {
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
- // Check expected storage mode
- assertHasFullStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28DefaultNotWhitelistedHasIsolatedAccess() throws Exception {
- try {
- // Install with no whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
- // Check expected storage mode
- assertHasIsolatedStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28OptInWhitelistedHasIsolatedAccess() throws Exception {
- try {
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
- // Check expected storage mode
- assertHasIsolatedStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28OptInNotWhitelistedHasIsolatedAccess() throws Exception {
- try {
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
- // Check expected storage mode
- assertHasIsolatedStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DefaultWhitelistedHasIsolatedAccess() throws Exception {
- try {
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
- // Check expected storage mode
- assertHasIsolatedStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DefaultNotWhitelistedHasIsolatedAccess() throws Exception {
- try {
- // Install with no whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/);
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/);
- // Check expected storage mode
- assertHasIsolatedStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29OptOutWhitelistedHasFullAccess() throws Exception {
- try {
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_OPT_OUT_29, null /*whitelistedPermissions*/);
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null /*whitelistedPermissions*/);
- // Check expected storage mode
- assertHasFullStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29OptOutNotWhitelistedHasIsolatedAccess() throws Exception {
- try {
- // Install with no whitelisted permissions.
- installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet() );
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet());
- // Check expected storage mode
- assertHasIsolatedStorageAccess();
- } finally {
- uninstallApp();
- }
+ // Check expected storage mode
+ assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
- public void testStorageDoesNotChangeOnUpdate() throws Exception {
- try {
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
+ public void testStorageTargetingSdk29CanOptOutViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
- // Check expected storage mode
- assertHasFullStorageAccess();
+ eventually(this::assertHasFullStorageAccess);
+ }
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk29CanOptOutViaDowngradeTo28() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
- // Check expected storage mode
- assertHasFullStorageAccess();
+ eventually(this::assertHasFullStorageAccess);
+ }
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/);
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk28CanRemoveOptInViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
- // Check expected storage mode
- assertHasFullStorageAccess();
- } finally {
- uninstallApp();
- }
+ eventually(this::assertHasFullStorageAccess);
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk28CanRemoveOptInByOptingOut() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+ eventually(this::assertHasFullStorageAccess);
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk28DoesNotLooseAccessWhenOptingIn() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+ eventually(this::assertHasFullStorageAccess);
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk28DoesNotLooseAccessViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_DEFAULT_28, null);
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+ eventually(this::assertHasFullStorageAccess);
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk29DoesNotLooseAccessViaUpdate() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+ eventually(this::assertHasFullStorageAccess);
+ }
+
+ @Test
+ @AppModeFull
+ public void testStorageTargetingSdk29DoesNotLooseAccessWhenOptingIn() throws Exception {
+ installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+ eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testCannotControlStorageWhitelistPostInstall1() throws Exception {
- try {
- // Install with whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
+ // Install with whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
- // Check expected state of restricted permissions.
- assertCannotUnWhitelistStorage();
- } finally {
- uninstallApp();
- }
+ // Check expected state of restricted permissions.
+ assertCannotUnWhitelistStorage();
}
@Test
@AppModeFull
public void testCannotControlStorageWhitelistPostInstall2() throws Exception {
- try {
- // Install with no whitelisted permissions.
- installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
+ // Install with no whitelisted permissions.
+ installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
- // Check expected state of restricted permissions.
- assertCannotWhitelistStorage();
- } finally {
- uninstallApp();
- }
+ // Check expected state of restricted permissions.
+ assertCannotWhitelistStorage();
}
private void assertHasFullStorageAccess() throws Exception {
@@ -609,17 +581,17 @@
PackageManager.GET_PERMISSIONS);
for (String permission : packageInfo.requestedPermissions) {
+ String op = AppOpsManager.permissionToOp(permission);
+
if (expectedWhitelistedPermissions != null
&& expectedWhitelistedPermissions.contains(permission)) {
- assertThat(appOpsManager.unsafeCheckOpNoThrow(
- AppOpsManager.permissionToOp(permission),
- packageInfo.applicationInfo.uid, PKG))
- .isEqualTo(AppOpsManager.MODE_ALLOWED);
+ assertThat(
+ appOpsManager.unsafeCheckOpNoThrow(op, packageInfo.applicationInfo.uid,
+ PKG)).named(op).isEqualTo(AppOpsManager.MODE_ALLOWED);
} else {
- assertThat(appOpsManager.unsafeCheckOpNoThrow(
- AppOpsManager.permissionToOp(permission),
- packageInfo.applicationInfo.uid, PKG))
- .isEqualTo(AppOpsManager.MODE_DEFAULT);
+ assertThat(
+ appOpsManager.unsafeCheckOpNoThrow(op, packageInfo.applicationInfo.uid,
+ PKG)).named(op).isEqualTo(AppOpsManager.MODE_DEFAULT);
}
}
});
@@ -705,7 +677,7 @@
private void installApp(@NonNull String app, @Nullable Set<String> whitelistedPermissions,
@Nullable Set<String> grantedPermissions) throws Exception {
// Install the app and whitelist/grant all permission if requested.
- final StringBuilder command = new StringBuilder("pm install ");
+ final StringBuilder command = new StringBuilder("pm install -r ");
if (whitelistedPermissions != null) {
command.append("--restrict-permissions ");
}
@@ -713,7 +685,8 @@
command.append("-g ");
}
command.append(app);
- runShellCommand(command.toString());
+ String installResult = runShellCommand(command.toString());
+ assertThat(installResult.trim()).isEqualTo("Success");
// Whitelist subset of permissions if requested
if (whitelistedPermissions != null && !whitelistedPermissions.isEmpty()) {
@@ -738,7 +711,8 @@
}
}
- private void uninstallApp() {
+ @After
+ public void uninstallApp() {
runShellCommand("pm uninstall " + PKG);
}
@@ -746,7 +720,7 @@
return InstrumentationRegistry.getInstrumentation().getContext();
}
- private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command)
+ private static void runWithShellPermissionIdentity(@NonNull Utils.ThrowingRunnable command)
throws Exception {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity();
diff --git a/tests/tests/permission2/src/android/permission2/cts/Utils.java b/tests/tests/permission2/src/android/permission2/cts/Utils.java
new file mode 100644
index 0000000..7cf2f4d
--- /dev/null
+++ b/tests/tests/permission2/src/android/permission2/cts/Utils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 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 andf
+ * limitations under the License.
+ */
+
+package android.permission2.cts;
+
+import androidx.annotation.NonNull;
+
+public class Utils {
+ private static final long TIMEOUT_MILLIS = 30000;
+
+ public interface ThrowingRunnable extends Runnable {
+ void runOrThrow() throws Exception;
+
+ @Override
+ default void run() {
+ try {
+ runOrThrow();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+
+ /**
+ * Make sure that a {@link ThrowingRunnable} eventually finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingRunnable} to run.
+ */
+ public static void eventually(@NonNull ThrowingRunnable r) throws Exception {
+ long start = System.currentTimeMillis();
+
+ while (true) {
+ try {
+ r.runOrThrow();
+ return;
+ } catch (Throwable e) {
+ if (System.currentTimeMillis() - start < TIMEOUT_MILLIS) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ throw e;
+ }
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
index c31491d..9e71c69 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
@@ -300,6 +300,30 @@
assertTrue(queryLong(uri, MediaColumns.DATE_ADDED) >= startTime);
}
+ @Test
+ public void testInPlaceUpdate_mediaFileWithInvalidRelativePath() throws Exception {
+ final File file = new File(ProviderTestUtils.stageDownloadDir(mVolumeName),
+ "test" + System.nanoTime() + ".jpg");
+ ProviderTestUtils.stageFile(R.raw.scenery, file);
+ Log.d(TAG, "Staged image file at " + file.getAbsolutePath());
+
+ final ContentValues insertValues = new ContentValues();
+ insertValues.put(MediaColumns.DATA, file.getAbsolutePath());
+ insertValues.put(MediaStore.Images.ImageColumns.DESCRIPTION, "Not a cat photo");
+ final Uri uri = mResolver.insert(mExternalImages, insertValues);
+ assertEquals(0, queryLong(uri, MediaStore.Images.ImageColumns.IS_PRIVATE));
+ assertStringColumn(uri, MediaStore.Images.ImageColumns.DESCRIPTION, "Not a cat photo");
+
+ final ContentValues updateValues = new ContentValues();
+ updateValues.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_IMAGE);
+ updateValues.put(FileColumns.MIME_TYPE, "image/jpeg");
+ updateValues.put(MediaStore.Images.ImageColumns.IS_PRIVATE, 1);
+ int updateRows = mResolver.update(uri, updateValues, null, null);
+ assertEquals(1, updateRows);
+ // Only interested in update not throwing exception. No need in checking whenever values
+ // were actually updates, as it is not in the scope of this test.
+ }
+
private long queryLong(Uri uri, String columnName) {
try (Cursor c = mResolver.query(uri, new String[] { columnName }, null, null, null)) {
assertTrue(c.moveToFirst());
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index 0150f2f..177fddb 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -19,6 +19,7 @@
import static android.provider.cts.MediaStoreTest.TAG;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -313,7 +314,7 @@
final Uri pendingUri = MediaStoreUtils.createPending(mContext, params);
final Uri publishUri;
try (PendingSession session = MediaStoreUtils.openPending(mContext, pendingUri)) {
- try (InputStream in = mContext.getResources().openRawResource(R.raw.volantis);
+ try (InputStream in = mContext.getResources().openRawResource(R.raw.lg_g4_iso_800_jpg);
OutputStream out = session.openOutputStream()) {
android.os.FileUtils.copy(in, out);
}
@@ -328,14 +329,19 @@
final ExifInterface exif = new ExifInterface(is);
final float[] latLong = new float[2];
exif.getLatLong(latLong);
- assertEquals(37.42303, latLong[0], 0.001);
- assertEquals(-122.162025, latLong[1], 0.001);
+ assertEquals(53.83451, latLong[0], 0.001);
+ assertEquals(10.69585, latLong[1], 0.001);
+
+ String xmp = exif.getAttribute(ExifInterface.TAG_XMP);
+ assertTrue("Failed to read XMP longitude", xmp.contains("53,50.070500N"));
+ assertTrue("Failed to read XMP latitude", xmp.contains("10,41.751000E"));
+ assertTrue("Failed to read non-location XMP", xmp.contains("LensDefaults"));
}
// As owner, we should be able to request the original bytes
try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
}
- // Now remove ownership, which means that Exif should be redacted
+ // Now remove ownership, which means that Exif/XMP location data should be redacted
ProviderTestUtils.executeShellCommand(
"content update --uri " + publishUri + " --bind owner_package_name:n:",
InstrumentationRegistry.getInstrumentation().getUiAutomation());
@@ -345,6 +351,11 @@
exif.getLatLong(latLong);
assertEquals(0, latLong[0], 0.001);
assertEquals(0, latLong[1], 0.001);
+
+ String xmp = exif.getAttribute(ExifInterface.TAG_XMP);
+ assertFalse("Failed to redact XMP longitude", xmp.contains("53,50.070500N"));
+ assertFalse("Failed to redact XMP latitude", xmp.contains("10,41.751000E"));
+ assertTrue("Redacted non-location XMP", xmp.contains("LensDefaults"));
}
// We can't request original bytes unless we have permission
try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
index 521b12b..06f0222 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
@@ -191,7 +191,7 @@
Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery,opts);
String stringUrl = null;
try{
- stringUrl = Media.insertImage(mContentResolver, src, null, null);
+ stringUrl = Media.insertImage(mContentResolver, src, "cts" + System.nanoTime(), null);
} catch (UnsupportedOperationException e) {
// the tests will be aborted because the image will be put in sdcard
fail("There is no sdcard attached! " + e.getMessage());
@@ -223,7 +223,7 @@
assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
// insert image, then delete it via the files table
- stringUrl = Media.insertImage(mContentResolver, src, null, null);
+ stringUrl = Media.insertImage(mContentResolver, src, "cts" + System.nanoTime(), null);
c = mContentResolver.query(Uri.parse(stringUrl),
new String[]{ Media._ID, Media.DATA}, null, null, null);
c.moveToFirst();
@@ -300,7 +300,8 @@
// insert an image
Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery);
- Uri uri = Uri.parse(Media.insertImage(mContentResolver, src, "test", "test description"));
+ Uri uri = Uri.parse(Media.insertImage(mContentResolver, src, "cts" + System.nanoTime(),
+ "test description"));
long imageId = ContentUris.parseId(uri);
assertNotNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
@@ -313,7 +314,8 @@
assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
// insert again
- uri = Uri.parse(Media.insertImage(mContentResolver, src, "test", "test description"));
+ uri = Uri.parse(Media.insertImage(mContentResolver, src, "cts" + System.nanoTime(),
+ "test description"));
imageId = ContentUris.parseId(uri);
// query its thumbnail again
@@ -326,6 +328,8 @@
assertEquals("unexpected number of updated rows",
1, mContentResolver.update(uri, values, null /* where */, null /* where args */));
+ SystemClock.sleep(1000);
+
// image was marked as regular file in the database, which should have deleted its thumbnail
assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MINI_KIND, null));
assertNull(Thumbnails.getThumbnail(resolver, imageId, Thumbnails.MICRO_KIND, null));
@@ -359,7 +363,8 @@
Uri url[] = new Uri[3];
try{
for (int i = 0; i < url.length; i++) {
- url[i] = Uri.parse(Media.insertImage(mContentResolver, src, null, null));
+ url[i] = Uri.parse(
+ Media.insertImage(mContentResolver, src, "cts" + System.nanoTime(), null));
mRowsAdded.add(url[i]);
long origId = Long.parseLong(url[i].getLastPathSegment());
Bitmap foo = MediaStore.Images.Thumbnails.getThumbnail(mContentResolver,
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
index 65c5154..fdf46ce3 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
@@ -21,6 +21,7 @@
import static android.provider.cts.ProviderTestUtils.assertNotExists;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -54,10 +55,12 @@
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
@Presubmit
@RunWith(Parameterized.class)
@@ -200,7 +203,7 @@
/**
* This test doesn't hold
- * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION}, so Exif
+ * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION}, so Exif and XMP
* location information should be redacted.
*/
@Test
@@ -232,6 +235,14 @@
assertEquals("+37.4217-122.0834/",
mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION));
}
+ try (InputStream in = mContentResolver.openInputStream(publishUri)) {
+ byte[] bytes = FileUtils.readInputStreamFully(in);
+ byte[] xmpBytes = Arrays.copyOfRange(bytes, 3269, 3269 + 13197);
+ String xmp = new String(xmpBytes);
+ assertTrue("Failed to read XMP longitude", xmp.contains("10,41.751000E"));
+ assertTrue("Failed to read XMP latitude", xmp.contains("53,50.070500N"));
+ assertTrue("Failed to read non-location XMP", xmp.contains("13166/7763"));
+ }
// As owner, we should be able to request the original bytes
try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
}
@@ -246,6 +257,14 @@
assertEquals(null,
mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION));
}
+ try (InputStream in = mContentResolver.openInputStream(publishUri)) {
+ byte[] bytes = FileUtils.readInputStreamFully(in);
+ byte[] xmpBytes = Arrays.copyOfRange(bytes, 3269, 3269 + 13197);
+ String xmp = new String(xmpBytes);
+ assertFalse("Failed to redact XMP longitude", xmp.contains("10,41.751000E"));
+ assertFalse("Failed to redact XMP latitude", xmp.contains("53,50.070500N"));
+ assertTrue("Redacted non-location XMP", xmp.contains("13166/7763"));
+ }
// We can't request original bytes unless we have permission
try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
fail("Able to read original content without ACCESS_MEDIA_LOCATION");
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
index 6d9a4bd..32ea780 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
@@ -164,6 +164,8 @@
assertEquals("unexpected number of updated rows",
1, mResolver.update(uri, values, null /* where */, null /* where args */));
+ SystemClock.sleep(1000);
+
// video was marked as regular file in the database, which should have deleted its thumbnail
assertNull(Thumbnails.getThumbnail(mResolver, Long.valueOf(uri.getLastPathSegment()),
Thumbnails.MINI_KIND, null /* options */));
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index 220ef47..e748360 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -183,6 +183,14 @@
"android.provider.cts");
}
+ static File stageDownloadDir(String volumeName) throws IOException {
+ if (MediaStore.VOLUME_EXTERNAL.equals(volumeName)) {
+ volumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY;
+ }
+ return Environment.buildPath(MediaStore.getVolumePath(volumeName),
+ Environment.DIRECTORY_DOWNLOADS, "android.provider.cts");
+ }
+
static File stageFile(int resId, File file) throws IOException {
// The caller may be trying to stage into a location only available to
// the shell user, so we need to perform the entire copy as the shell
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
index ef992e6..8a78d0c 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
@@ -28,7 +28,7 @@
ctstestrunner-axt \
compatibility-device-util-axt
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 29
LOCAL_JAVA_LIBRARIES += android.test.runner
LOCAL_JAVA_LIBRARIES += android.test.base
# Tag this module as a cts test artifact
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/OWNERS b/tests/tests/secure_element/access_control/AccessControlApp1/OWNERS
deleted file mode 100644
index 9af5f4d..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp1/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 456592
-kandoiruchi@google.com
\ No newline at end of file
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
index 28cb203..d82007a 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
index 38f12ee..494125f 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
@@ -28,7 +28,7 @@
ctstestrunner-axt \
compatibility-device-util-axt
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 29
LOCAL_JAVA_LIBRARIES += android.test.runner
LOCAL_JAVA_LIBRARIES += android.test.base
# Tag this module as a cts test artifact
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/OWNERS b/tests/tests/secure_element/access_control/AccessControlApp2/OWNERS
deleted file mode 100644
index 9af5f4d..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp2/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 456592
-kandoiruchi@google.com
\ No newline at end of file
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
index 1769767..6c8cb70 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
index 335c08a..11f0200 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
@@ -28,7 +28,7 @@
ctstestrunner-axt \
compatibility-device-util-axt
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 29
LOCAL_JAVA_LIBRARIES += android.test.runner
LOCAL_JAVA_LIBRARIES += android.test.base
# Tag this module as a cts test artifact
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/OWNERS b/tests/tests/secure_element/access_control/AccessControlApp3/OWNERS
deleted file mode 100644
index 9af5f4d..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp3/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 456592
-kandoiruchi@google.com
\ No newline at end of file
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
index ab07811..4d8f5e3 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/OWNERS b/tests/tests/secure_element/access_control/OWNERS
new file mode 100644
index 0000000..853b7c3
--- /dev/null
+++ b/tests/tests/secure_element/access_control/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 456592
+zachoverflow@google.com
+jackcwyu@google.com
+tokuda@google.com
+georgekgchang@google.com
+jimmychchang@google.com
diff --git a/tests/tests/security/src/android/security/cts/RenderTarget.java b/tests/tests/security/src/android/security/cts/RenderTarget.java
new file mode 100644
index 0000000..3c0d1c4
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/RenderTarget.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2019 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 android.security.cts;
+
+import static android.opengl.EGL14.EGL_ALPHA_SIZE;
+import static android.opengl.EGL14.EGL_BLUE_SIZE;
+import static android.opengl.EGL14.EGL_CONFIG_CAVEAT;
+import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
+import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
+import static android.opengl.EGL14.EGL_DEPTH_SIZE;
+import static android.opengl.EGL14.EGL_GREEN_SIZE;
+import static android.opengl.EGL14.EGL_HEIGHT;
+import static android.opengl.EGL14.EGL_NONE;
+import static android.opengl.EGL14.EGL_NO_CONTEXT;
+import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
+import static android.opengl.EGL14.EGL_RED_SIZE;
+import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
+import static android.opengl.EGL14.EGL_SURFACE_TYPE;
+import static android.opengl.EGL14.EGL_WIDTH;
+import static android.opengl.EGL14.EGL_WINDOW_BIT;
+import static android.opengl.EGL14.eglChooseConfig;
+import static android.opengl.EGL14.eglCreateContext;
+import static android.opengl.EGL14.eglCreatePbufferSurface;
+import static android.opengl.EGL14.eglGetDisplay;
+import static android.opengl.EGL14.eglInitialize;
+import static android.opengl.EGL14.eglMakeCurrent;
+import static android.opengl.GLES20.glDeleteTextures;
+import static android.opengl.GLES20.glGenTextures;
+
+import android.graphics.SurfaceTexture;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSurface;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Log;
+import android.view.Surface;
+
+public final class RenderTarget {
+ static final String TAG = "RenderTarget";
+
+ private static final int SETUP_THREAD = 1;
+ private static final int CREATE_SINK = 2;
+ private static final int DESTROY_SINK = 3;
+ private static final int UPDATE_TEX_IMAGE = 4;
+
+ private static final Handler sHandler;
+ static {
+ HandlerThread thread = new HandlerThread("RenderTarget-GL");
+ thread.start();
+ sHandler = new Handler(thread.getLooper(), new RenderTargetThread());
+ sHandler.sendEmptyMessage(SETUP_THREAD);
+ }
+
+ public static RenderTarget create() {
+ GenericFuture<RenderTarget> future = new GenericFuture<>();
+ Message.obtain(sHandler, CREATE_SINK, future).sendToTarget();
+ try {
+ return future.get();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to createSink()", e);
+ }
+ }
+
+ private final SurfaceTexture mSurfaceTexture;
+ private final int mGlTexId;
+ private Surface mSurface;
+
+ private RenderTarget(SurfaceTexture surfaceTexture, int glTexId) {
+ mSurfaceTexture = surfaceTexture;
+ mGlTexId = glTexId;
+ mSurface = new Surface(mSurfaceTexture);
+ }
+
+ public Surface getSurface() {
+ return mSurface;
+ }
+
+ public void setDefaultSize(int width, int height) {
+ mSurfaceTexture.setDefaultBufferSize(width, height);
+ }
+
+ public void destroy() {
+ mSurface = null;
+ Message.obtain(sHandler, DESTROY_SINK, this).sendToTarget();
+ }
+
+ private static class RenderTargetThread implements Handler.Callback,
+ SurfaceTexture.OnFrameAvailableListener {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case SETUP_THREAD:
+ setupThread();
+ return true;
+ case CREATE_SINK:
+ createSink((GenericFuture<RenderTarget>) msg.obj);
+ return true;
+ case DESTROY_SINK:
+ destroySink((RenderTarget) msg.obj);
+ return true;
+ case UPDATE_TEX_IMAGE:
+ updateTexImage((SurfaceTexture) msg.obj);
+ default:
+ return false;
+ }
+ }
+
+ private void createSink(GenericFuture<RenderTarget> sinkFuture) {
+ int[] tex = new int[1];
+ glGenTextures(1, tex, 0);
+ SurfaceTexture texture = new SurfaceTexture(tex[0]);
+ texture.setOnFrameAvailableListener(this);
+ sinkFuture.setResult(new RenderTarget(texture, tex[0]));
+ }
+
+ private void destroySink(RenderTarget sink) {
+ sHandler.removeMessages(UPDATE_TEX_IMAGE, sink.mSurfaceTexture);
+ sink.mSurfaceTexture.setOnFrameAvailableListener(null);
+ sink.mSurfaceTexture.release();
+ glDeleteTextures(1, new int[] { sink.mGlTexId }, 0);
+ }
+
+ private void updateTexImage(SurfaceTexture texture) {
+ texture.updateTexImage();
+ }
+
+ private void setupThread() {
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (display == null) {
+ throw new IllegalStateException("eglGetDisplay failed");
+ }
+ int[] version = new int[2];
+ if (!eglInitialize(display, version, 0, version, 1)) {
+ throw new IllegalStateException("eglInitialize failed");
+ }
+ final int[] egl_attribs = new int[] {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 0,
+ EGL_CONFIG_CAVEAT, EGL_NONE,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] num_configs = new int[1];
+ if (!eglChooseConfig(display, egl_attribs, 0, configs, 0, 1, num_configs, 0)
+ || num_configs[0] <= 0 || configs[0] == null) {
+ throw new IllegalStateException("eglChooseConfig failed");
+ }
+ EGLConfig config = configs[0];
+ final int[] gl_attribs = new int[] {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+ EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, gl_attribs, 0);
+ if (context == null) {
+ throw new IllegalStateException("eglCreateContext failed");
+ }
+ final int[] pbuffer_attribs = new int[] { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+ EGLSurface pbuffer = eglCreatePbufferSurface(display, config, pbuffer_attribs, 0);
+ if (pbuffer == null) {
+ throw new IllegalStateException("create pbuffer surface failed");
+ }
+ if (!eglMakeCurrent(display, pbuffer, pbuffer, context)) {
+ throw new IllegalStateException("Failed to make current");
+ }
+ }
+
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ Log.i(TAG, "new frame available");
+ Message.obtain(sHandler, UPDATE_TEX_IMAGE, surfaceTexture).sendToTarget();
+ }
+ }
+
+ private static class GenericFuture<T> {
+ private boolean mHasResult = false;
+ private T mResult;
+ public void setResult(T result) {
+ synchronized (this) {
+ if (mHasResult) {
+ throw new IllegalStateException("Result already set");
+ }
+ mHasResult = true;
+ mResult = result;
+ notifyAll();
+ }
+ }
+
+ public T get() throws InterruptedException {
+ synchronized (this) {
+ while (!mHasResult) {
+ wait();
+ }
+ return mResult;
+ }
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 7b9cef0..b0e15e1 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -845,7 +845,8 @@
mp.setOnErrorListener(mpcl);
mp.setOnPreparedListener(mpcl);
mp.setOnCompletionListener(mpcl);
- Surface surface = getDummySurface();
+ RenderTarget renderTarget = RenderTarget.create();
+ Surface surface = renderTarget.getSurface();
mp.setSurface(surface);
AssetFileDescriptor fd = null;
try {
@@ -858,6 +859,7 @@
}
Looper.loop();
mp.release();
+ renderTarget.destroy();
}
});
t.start();
@@ -1109,32 +1111,6 @@
doStagefrightTestMediaPlayerANR(rid, null);
}
- private Surface getDummySurface() {
- int[] textures = new int[1];
- GLES20.glGenTextures(1, textures, 0);
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES20.GL_TEXTURE_MIN_FILTER,
- GLES20.GL_NEAREST);
- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES20.GL_TEXTURE_MAG_FILTER,
- GLES20.GL_LINEAR);
- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES20.GL_TEXTURE_WRAP_S,
- GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES20.GL_TEXTURE_WRAP_T,
- GLES20.GL_CLAMP_TO_EDGE);
- SurfaceTexture surfaceTex = new SurfaceTexture(textures[0]);
- surfaceTex.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- Log.i(TAG, "new frame available");
- }
- });
- return new Surface(surfaceTex);
- }
-
public JSONArray getCrashReport(String testname, long timeout)
throws InterruptedException {
Log.i(TAG, CrashUtils.UPLOAD_REQUEST);
@@ -1297,7 +1273,8 @@
mp.setOnErrorListener(mpcl);
mp.setOnPreparedListener(mpcl);
mp.setOnCompletionListener(mpcl);
- Surface surface = getDummySurface();
+ RenderTarget renderTarget = RenderTarget.create();
+ Surface surface = renderTarget.getSurface();
mp.setSurface(surface);
AssetFileDescriptor fd = null;
try {
@@ -1320,6 +1297,7 @@
Looper.loop();
mp.release();
+ renderTarget.destroy();
}
});
@@ -1440,9 +1418,10 @@
Log.i(TAG, "Decoding track " + t + " using codec " + codecName);
ex.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
MediaCodec codec = MediaCodec.createByCodecName(codecName);
+ RenderTarget renderTarget = RenderTarget.create();
Surface surface = null;
if (mime.startsWith("video/")) {
- surface = getDummySurface();
+ surface = renderTarget.getSurface();
}
try {
codec.configure(format, surface, null, 0);
@@ -1484,6 +1463,7 @@
// local exceptions ignored, not security issues
} finally {
codec.release();
+ renderTarget.destroy();
}
}
ex.unselectTrack(t);
@@ -1921,7 +1901,8 @@
mp.setOnErrorListener(mpl);
mp.setOnPreparedListener(mpl);
mp.setOnCompletionListener(mpl);
- Surface surface = getDummySurface();
+ RenderTarget renderTarget = RenderTarget.create();
+ Surface surface = renderTarget.getSurface();
mp.setSurface(surface);
AssetFileDescriptor fd = null;
try {
@@ -1943,6 +1924,7 @@
Looper.loop();
mp.release();
+ renderTarget.destroy();
}
});
diff --git a/tests/tests/systemui/OWNERS b/tests/tests/systemui/OWNERS
index 958a89a..583baa0 100644
--- a/tests/tests/systemui/OWNERS
+++ b/tests/tests/systemui/OWNERS
@@ -1,2 +1,4 @@
# Bug component: 136515
evanlaird@google.com
+felkachang@google.com
+
diff --git a/tests/tests/systemui/src/android/systemui/cts/TouchHelper.java b/tests/tests/systemui/src/android/systemui/cts/TouchHelper.java
new file mode 100644
index 0000000..1ad74b9
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/TouchHelper.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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 android.systemui.cts;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.os.SystemClock;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+
+public class TouchHelper {
+
+ private static final long REGULAR_CLICK_LENGTH = 100;
+ private final UiAutomation mUiAutomation;
+ private long mDownTime = 0;
+
+ public TouchHelper(Instrumentation instrumentation) {
+ mUiAutomation = instrumentation.getUiAutomation();
+ }
+
+ /**
+ * To click (x, y) without checking the boundary.
+ *
+ * @param x the x position on the screen
+ * @param y the y position on the screen
+ * @return true if the click event inject success, otherwise false
+ */
+ public boolean click(int x, int y) {
+ if (touchDown(x, y)) {
+ SystemClock.sleep(REGULAR_CLICK_LENGTH);
+ if (touchUp(x, y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean touchDown(int x, int y) {
+ mDownTime = SystemClock.uptimeMillis();
+ MotionEvent event = getMotionEvent(mDownTime, mDownTime, MotionEvent.ACTION_DOWN, x, y);
+ return injectEventSync(event);
+ }
+
+ private boolean touchUp(int x, int y) {
+ final long eventTime = SystemClock.uptimeMillis();
+ MotionEvent event = getMotionEvent(mDownTime, eventTime, MotionEvent.ACTION_UP, x, y);
+ mDownTime = 0;
+ return injectEventSync(event);
+ }
+
+ private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
+ float x, float y) {
+
+ MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
+ properties.id = 0;
+ properties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+
+ MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+ coords.pressure = 1;
+ coords.size = 1;
+ coords.x = x;
+ coords.y = y;
+
+ return MotionEvent.obtain(downTime, eventTime, action, 1,
+ new MotionEvent.PointerProperties[] { properties },
+ new MotionEvent.PointerCoords[] { coords },
+ 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+ }
+
+ private boolean injectEventSync(InputEvent event) {
+ return mUiAutomation.injectInputEvent(event, true);
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java
index 30ee9b8..7543c20 100644
--- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java
+++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java
@@ -16,11 +16,16 @@
package android.systemui.cts;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+
import android.annotation.MainThread;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -35,6 +40,7 @@
public class WindowInsetsActivity extends LightBarBaseActivity implements View.OnClickListener,
View.OnApplyWindowInsetsListener {
+ private static final int DISPLAY_CUTOUT_SLACK_DP = 20;
private TextView mContent;
private boolean mIsSetViewBound;
@@ -46,6 +52,7 @@
private Consumer<Boolean> mInitialFinishCallBack;
private int mClickCount;
private Consumer<View> mClickConsumer;
+ private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
/**
@@ -71,12 +78,21 @@
mContent.setOnApplyWindowInsetsListener(this::onApplyWindowInsets);
mContent.getRootView().setOnApplyWindowInsetsListener(this::onApplyWindowInsets);
getWindow().getDecorView().setOnApplyWindowInsetsListener(this::onApplyWindowInsets);
+ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ getWindow().getAttributes().layoutInDisplayCutoutMode
+ = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setStatusBarColor(0x22ff0000);
+ getWindow().setNavigationBarColor(0x22ff0000);
mContent.setOnClickListener(this);
mContent.requestApplyInsets();
setContentView(mContent);
mContentWindowInsets = getWindow().getDecorView().getRootWindowInsets();
mInitialFinishCallBack = null;
+
+ getDisplay().getRealMetrics(mDisplayMetrics);
}
@Override
@@ -198,6 +214,21 @@
sb.append("content boundary = ").append(mContentBound).append("\n");
}
+ Display display = getDisplay();
+ if (display != null) {
+ sb.append("------------------------").append("\n");
+ DisplayCutout displayCutout = display.getCutout();
+ if (displayCutout != null) {
+ sb.append("displayCutout = ").append(displayCutout.toString()).append("\n");
+ } else {
+ sb.append("Display cut out = null\n");
+ }
+
+ sb.append("real size = (").append(mDisplayMetrics.widthPixels).append(",")
+ .append(mDisplayMetrics.heightPixels).append(")\n");
+ }
+
+
mContent.setText(sb.toString());
}
@@ -217,30 +248,30 @@
/**
* To count the draggable boundary that has consume the related insets.
**/
-
@MainThread
- public Rect getOperationArea(boolean insetMandatorySystemGesture,
- boolean insetTappableElements, WindowInsets windowInsets) {
-
- Insets insets;
- if (insetMandatorySystemGesture) {
- insets = windowInsets.getMandatorySystemGestureInsets();
- } else if (insetTappableElements) {
- insets = windowInsets.getTappableElementInsets();
- } else {
- insets = windowInsets.getSystemGestureInsets();
- }
-
+ public Rect getOperationArea(Insets insets, WindowInsets windowInsets) {
int left = insets.left;
- int top = 0;
- if (windowInsets.getStableInsetTop() >= insets.top) {
- top = windowInsets.getStableInsetTop() - insets.top;
- } else {
- top = insets.top;
- }
+ int top = insets.top;
int right = insets.right;
int bottom = insets.bottom;
+ final DisplayCutout cutout = windowInsets.getDisplayCutout();
+ if (cutout != null) {
+ int slack = (int) (DISPLAY_CUTOUT_SLACK_DP * mDisplayMetrics.density);
+ if (cutout.getSafeInsetLeft() > 0) {
+ left = Math.max(left, cutout.getSafeInsetLeft() + slack);
+ }
+ if (cutout.getSafeInsetTop() > 0) {
+ top = Math.max(top, cutout.getSafeInsetTop() + slack);
+ }
+ if (cutout.getSafeInsetRight() > 0) {
+ right = Math.max(right, cutout.getSafeInsetRight() + slack);
+ }
+ if (cutout.getSafeInsetBottom() > 0) {
+ bottom = Math.max(bottom, cutout.getSafeInsetBottom() + slack);
+ }
+ }
+
Rect windowBoundary = getViewBound(getContentView());
Rect rect = new Rect(windowBoundary);
rect.left += left;
diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
index 11d40a0..2ca4156 100644
--- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
@@ -23,6 +23,7 @@
import static org.junit.Assume.assumeTrue;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -30,6 +31,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
+import android.os.Bundle;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
@@ -63,9 +65,11 @@
private static final String DEF_SCREENSHOT_BASE_PATH =
"/sdcard/WindowInsetsBehaviorTests";
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
- public static final int STEPS = 10;
- public static final int DIP_INTERVAL = 40;
+ private static final String ARGUMENT_KEY_FORCE_ENABLE = "force_enable_gesture_navigation";
+ private static final int STEPS = 10;
+ private static final int DIP_INTERVAL = 40;
+ private final boolean mForceEnableGestureNavigation;
private final Map<String, Boolean> mSystemGestureOptionsMap;
private float mPixelsPerDp;
private UiDevice mDevice;
@@ -73,6 +77,7 @@
private String mEdgeToEdgeNavigationTitle;
private String mSystemNavigationTitle;
private String mGesturePreferenceTitle;
+ private TouchHelper mTouchHelper;
private boolean mConfiguredInSettings;
private static String getSettingsString(Resources res, String strResName) {
@@ -88,8 +93,16 @@
* To initial all of options in System Gesture.
*/
public WindowInsetsBehaviorTests() {
+ Bundle bundle = InstrumentationRegistry.getArguments();
+ mForceEnableGestureNavigation = (bundle != null)
+ && "true".equalsIgnoreCase(bundle.getString(ARGUMENT_KEY_FORCE_ENABLE));
+
mSystemGestureOptionsMap = new ArrayMap();
+ if (!mForceEnableGestureNavigation) {
+ return;
+ }
+
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
PackageManager packageManager = context.getPackageManager();
Resources res = null;
@@ -173,14 +186,17 @@
return mDevice.findObject(targetSelector);
}
-
private boolean launchToSettingsSystemGesture() {
+ if (!mForceEnableGestureNavigation) {
+ return false;
+ }
+
/* launch to the close to the system gesture fragment */
- Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.Settings$SystemDashboardActivity");
- intent.putExtra(":settings:show_fragment",
- "com.android.settings.gestures.GestureSettings");
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ ComponentName settingComponent = new ComponentName(SETTINGS_PACKAGE_NAME,
+ String.format("%s.%s$%s", SETTINGS_PACKAGE_NAME, "Settings",
+ "SystemDashboardActivity"));
+ intent.setComponent(settingComponent);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mTargetContext.startActivity(intent);
@@ -230,6 +246,7 @@
@Before
public void setUp() throws Exception {
mDevice = UiDevice.getInstance(getInstrumentation());
+ mTouchHelper = new TouchHelper(getInstrumentation());
mTargetContext = getInstrumentation().getTargetContext();
if (!hasSystemGestureFeature()) {
return;
@@ -303,7 +320,10 @@
mActivity.setOnClickConsumer((view) -> {
latch.countDown();
});
- mDevice.click(p.x, p.y);
+ // mDevice.click(p.x, p.y) has the limitation without consideration of the cutout
+ if (!mTouchHelper.click(p.x, p.y)) {
+ fail("Can't inject event at" + p);
+ }
/* wait until the OnClickListener triggered, and then click the next point */
try {
@@ -313,7 +333,7 @@
}
if (latch.getCount() > 0) {
- fail("Doesn't receive onClickEvent");
+ fail("Doesn't receive onClickEvent at " + p);
}
}
@@ -514,8 +534,9 @@
mainThreadRun(() -> mActivity.setSystemGestureExclusion(true));
mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
- mainThreadRun(() -> mDragBound = mActivity.getOperationArea(true,
- false, mContentViewWindowInsets));
+ mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+ mContentViewWindowInsets.getMandatorySystemGestureInsets(),
+ mContentViewWindowInsets));
int dragCount = dragInViewBoundary(mDragBound);
@@ -532,35 +553,13 @@
}
@Test
- public void mandatorySystemGesture_tapSamplePoints_excludeViewRects_withoutAnyCancel() {
- assumeTrue(hasSystemGestureFeature());
-
- mainThreadRun(() -> mActivity.setSystemGestureExclusion(true));
- mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
- mainThreadRun(() -> mDragBound = mActivity.getOperationArea(false,
- true, mContentViewWindowInsets));
-
- int count = clickAllOfSamplePoints(mDragBound, this::clickAndWaitByUiDevice);
-
- mainThreadRun(() -> {
- mClickCount = mActivity.getClickCount();
- mActionCancelPoints = mActivity.getActionCancelPoints();
- });
- mScreenshotTestRule.capture();
-
- assertEquals("The number of click not match", count, mClickCount);
- assertEquals("The Number of the canceled points not match", 0,
- mActionCancelPoints.size());
- }
-
- @Test
public void systemGesture_notExcludeViewRects_withoutAnyCancel() {
assumeTrue(hasSystemGestureFeature());
mainThreadRun(() -> mActivity.setSystemGestureExclusion(false));
mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
- mainThreadRun(() -> mDragBound = mActivity.getOperationArea(false,
- false, mContentViewWindowInsets));
+ mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+ mContentViewWindowInsets.getSystemGestureInsets(), mContentViewWindowInsets));
int dragCount = dragInViewBoundary(mDragBound);
@@ -577,13 +576,13 @@
}
@Test
- public void systemGesture_tapSamplePoints_notExcludeViewRects_withoutAnyCancel() {
+ public void tappableElements_tapSamplePoints_excludeViewRects_withoutAnyCancel() {
assumeTrue(hasSystemGestureFeature());
- mainThreadRun(() -> mActivity.setSystemGestureExclusion(false));
+ mainThreadRun(() -> mActivity.setSystemGestureExclusion(true));
mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
- mainThreadRun(() -> mDragBound = mActivity.getOperationArea(false,
- true, mContentViewWindowInsets));
+ mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+ mContentViewWindowInsets.getTappableElementInsets(), mContentViewWindowInsets));
int count = clickAllOfSamplePoints(mDragBound, this::clickAndWaitByUiDevice);
@@ -598,19 +597,14 @@
mActionCancelPoints.size());
}
- /**
- * To tap all possible points except the system gesture area and tappable elements area.
- * Caution: don't touch system gesture area because it still exists and will trigger cancel
- * event.
- */
@Test
public void tappableElements_tapSamplePoints_notExcludeViewRects_withoutAnyCancel() {
assumeTrue(hasSystemGestureFeature());
mainThreadRun(() -> mActivity.setSystemGestureExclusion(false));
mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
- mainThreadRun(() -> mDragBound = mActivity.getOperationArea(false,
- true, mContentViewWindowInsets));
+ mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+ mContentViewWindowInsets.getTappableElementInsets(), mContentViewWindowInsets));
int count = clickAllOfSamplePoints(mDragBound, this::clickAndWaitByUiDevice);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index e058947..f1acc16 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -220,6 +220,6 @@
initBlueWebView(hwFence), true, hwFence)
.addLayout(R.layout.circle_clipped_webview,
initBlueWebView(swFence), false, swFence)
- .runWithComparer(new MSSIMComparer(0.95));
+ .runWithComparer(new MSSIMComparer(0.94));
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewFadingEdgeTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewFadingEdgeTests.java
new file mode 100644
index 0000000..81b1586
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewFadingEdgeTests.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2019 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 android.uirendering.cts.testclasses;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.ViewInitializer;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewFadingEdgeTests extends ActivityTestBase {
+ class FadingView extends View {
+ public boolean mEnableFadingLeftEdge = false;
+ public boolean mEnableFadingRightEdge = false;
+ public boolean mEnableFadingTopEdge = false;
+ public boolean mEnableFadingBottomEdge = false;
+
+ FadingView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawColor(Color.RED);
+ }
+
+ @Override
+ protected float getLeftFadingEdgeStrength() {
+ return mEnableFadingLeftEdge ? 1.0f : 0.0f;
+ }
+
+ @Override
+ protected float getRightFadingEdgeStrength() {
+ return mEnableFadingRightEdge ? 1.0f : 0.0f;
+ }
+
+ @Override
+ protected float getTopFadingEdgeStrength() {
+ return mEnableFadingTopEdge ? 1.0f : 0.0f;
+ }
+
+ @Override
+ protected float getBottomFadingEdgeStrength() {
+ return mEnableFadingBottomEdge ? 1.0f : 0.0f;
+ }
+ }
+
+ private FadingView attachFadingView(View parentView) {
+ final FadingView child = new FadingView(parentView.getContext());
+ child.setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ FrameLayout root = (FrameLayout) parentView.findViewById(R.id.frame_layout);
+ root.addView(child);
+ return child;
+ }
+
+ @Test
+ public void testCreateLeftFade() {
+ createTest()
+ .addLayout(R.layout.frame_layout, (ViewInitializer) view -> {
+ final FadingView child = attachFadingView(view);
+ child.mEnableFadingLeftEdge = true;
+ child.setFadingEdgeLength(TEST_WIDTH / 2);
+ child.setHorizontalFadingEdgeEnabled(true);
+ Assert.assertEquals(0, child.getSolidColor());
+ })
+ .runWithVerifier(new SamplePointVerifier(new Point[] {
+ new Point(0, 0),
+ new Point(TEST_WIDTH / 4, 0),
+ new Point(TEST_WIDTH / 2, 0),
+ new Point(TEST_WIDTH - 1, 0)
+ }, new int[] {
+ Color.WHITE,
+ 0xFFFF8080, // gradient halfway between red and white
+ Color.RED,
+ Color.RED,
+
+ }, 20)); // Tolerance set to account for interpolation
+ }
+
+ @Test
+ public void testCreateRightFade() {
+ createTest()
+ .addLayout(R.layout.frame_layout, (ViewInitializer) view -> {
+ final FadingView child = attachFadingView(view);
+ child.mEnableFadingRightEdge = true;
+ child.setFadingEdgeLength(TEST_WIDTH / 2);
+ child.setHorizontalFadingEdgeEnabled(true);
+ Assert.assertEquals(0, child.getSolidColor());
+ })
+ .runWithVerifier(new SamplePointVerifier(new Point[] {
+ new Point(0, 0),
+ new Point(TEST_WIDTH / 2, 0),
+ new Point((TEST_WIDTH / 4) * 3, 0),
+ new Point(TEST_WIDTH - 1, 0)
+ }, new int[] {
+ Color.RED,
+ Color.RED,
+ 0xFFFF8080, // gradient halfway between red and white
+ Color.WHITE
+ }, 20)); // Tolerance set to account for interpolation
+ }
+
+ @Test
+ public void testCreateTopFade() {
+ createTest()
+ .addLayout(R.layout.frame_layout, (ViewInitializer) view -> {
+ final FadingView child = attachFadingView(view);
+ child.mEnableFadingTopEdge = true;
+ child.setFadingEdgeLength(TEST_HEIGHT / 2);
+ child.setVerticalFadingEdgeEnabled(true);
+ Assert.assertEquals(0, child.getSolidColor());
+ })
+ .runWithVerifier(new SamplePointVerifier(new Point[] {
+ new Point(0, 0),
+ new Point(0, TEST_HEIGHT / 4),
+ new Point(0, TEST_HEIGHT / 2),
+ new Point(0, TEST_HEIGHT - 1)
+ }, new int[] {
+ Color.WHITE,
+ 0xFFFF8080, // gradient halfway between red and white
+ Color.RED,
+ Color.RED,
+ }, 20)); // Tolerance set to account for interpolation
+ }
+
+ @Test
+ public void testCreateBottomFade() {
+ createTest()
+ .addLayout(R.layout.frame_layout, (ViewInitializer) view -> {
+ final FadingView child = attachFadingView(view);
+ child.mEnableFadingBottomEdge = true;
+ child.setFadingEdgeLength(TEST_HEIGHT / 2);
+ child.setVerticalFadingEdgeEnabled(true);
+ Assert.assertEquals(0, child.getSolidColor());
+ })
+ .runWithVerifier(new SamplePointVerifier(new Point[] {
+ new Point(0, 0),
+ new Point(0, TEST_HEIGHT / 2),
+ new Point(0, (TEST_HEIGHT / 4) * 3),
+ new Point(0, TEST_HEIGHT - 1)
+ }, new int[] {
+ Color.RED,
+ Color.RED,
+ 0xFFFF8080, // gradient halfway between red and white
+ Color.WHITE
+ }, 20)); // Tolerance set to account for interpolation
+ }
+
+ @Test
+ public void testCreateLeftAndRightFade() {
+ createTest()
+ .addLayout(R.layout.frame_layout, (ViewInitializer) view -> {
+ final FadingView child = attachFadingView(view);
+ child.mEnableFadingLeftEdge = true;
+ child.mEnableFadingRightEdge = true;
+ child.setFadingEdgeLength(TEST_WIDTH / 2);
+ child.setHorizontalFadingEdgeEnabled(true);
+ Assert.assertEquals(0, child.getSolidColor());
+ })
+ .runWithVerifier(new SamplePointVerifier(new Point[] {
+ new Point(0, 0),
+ new Point(TEST_WIDTH / 4, 0),
+ new Point(TEST_WIDTH / 2, 0),
+ new Point((TEST_WIDTH / 4) * 3, 0),
+ new Point(TEST_WIDTH - 1, 0)
+ }, new int[] {
+ Color.WHITE,
+ 0xFFFF8080, // gradient halfway between red and white
+ Color.RED,
+ 0xFFFF8080, // gradient halfway between red and white
+ Color.WHITE
+ }, 20)); // Tolerance set to account for interpolation
+ }
+}
diff --git a/tests/tests/voiceinteraction/AndroidManifest.xml b/tests/tests/voiceinteraction/AndroidManifest.xml
index 86ae911..393d7a8 100644
--- a/tests/tests/voiceinteraction/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/AndroidManifest.xml
@@ -16,8 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.voiceinteraction.cts"
- android:targetSandboxVersion="2">
+ package="android.voiceinteraction.cts">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
@@ -36,12 +35,7 @@
<activity android:name="TestLocalInteractionActivity"
android:label="Local Interaction Activity">
<intent-filter>
- <action android:name="android.intent.action.VIEW"/>
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="https" />
- <data android:host="android.voiceinteraction.cts" />
- <data android:path="/TestLocalInteractionActivity" />
+ <action android:name="android.intent.action.TEST_LOCAL_INTERACTION_ACTIVITY" />
</intent-filter>
</activity>
<receiver android:name="VoiceInteractionTestReceiver"
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index 461fc6b..bbf478d 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -19,17 +19,20 @@
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="not-shardable" value="true" />
+
+ <!-- Force service to be installed as non-instant mode, always -->
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsVoiceInteractionService.apk" />
- <option name="test-file-name" value="CtsVoiceInteractionApp.apk" />
- <option name="test-file-name" value="CtsVoiceInteractionTestCases.apk" />
+ <option name="instant-mode" value="false"/>
+ <option name="force-install-mode" value="FULL"/>
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="CtsVoiceInteractionService.apk"/>
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="cmd voiceinteraction set bind-instant-service-allowed true" />
- <option name="teardown-command" value="cmd voiceinteraction set bind-instant-service-allowed false" />
- </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsVoiceInteractionTestCases.apk"/>
+ <option name="test-file-name" value="CtsVoiceInteractionApp.apk"/>
+ </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.voiceinteraction.cts" />
diff --git a/tests/tests/voiceinteraction/service/AndroidManifest.xml b/tests/tests/voiceinteraction/service/AndroidManifest.xml
index 2ef0728..b01653c 100644
--- a/tests/tests/voiceinteraction/service/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/service/AndroidManifest.xml
@@ -24,21 +24,26 @@
android:label="CTS test voice interaction service"
android:permission="android.permission.BIND_VOICE_INTERACTION"
android:process=":interactor"
- android:exported="true">
+ android:exported="true"
+ android:visibleToInstantApps="true">
<meta-data android:name="android.voice_interaction"
android:resource="@xml/interaction_service" />
<intent-filter>
<action android:name="android.service.voice.VoiceInteractionService" />
</intent-filter>
</service>
- <activity android:name=".VoiceInteractionMain">
+ <activity android:name=".VoiceInteractionMain"
+ android:exported="true"
+ android:visibleToInstantApps="true">
<intent-filter>
<action android:name="android.intent.action.START_TEST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".SettingsActivity"
- android:label="Voice Interaction Settings">
+ android:label="Voice Interaction Settings"
+ android:exported="true"
+ android:visibleToInstantApps="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -46,10 +51,14 @@
</activity>
<service android:name=".MainInteractionSessionService"
android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":session">
+ android:process=":session"
+ android:exported="true"
+ android:visibleToInstantApps="true">
</service>
<service android:name=".MainRecognitionService"
- android:label="CTS Voice Recognition Service">
+ android:label="CTS Voice Recognition Service"
+ android:exported="true"
+ android:visibleToInstantApps="true">
<intent-filter>
<action android:name="android.speech.RecognitionService" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainInteractionService.java b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainInteractionService.java
index ca92286..ccd20e5 100644
--- a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainInteractionService.java
+++ b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainInteractionService.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionSession;
@@ -60,10 +61,14 @@
// Call to verify onGetSupportedVoiceActions is available.
onGetSupportedVoiceActions(Collections.emptySet());
args = new Bundle();
- Intent intent = new Intent();
- intent.setComponent(new ComponentName("android.voiceinteraction.testapp",
- "android.voiceinteraction.testapp.TestApp"));
+ Intent intent = new Intent()
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_VOICE)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse("https://android.voiceinteraction.testapp"
+ + "/TestApp"));
args.putParcelable("intent", intent);
+ Log.v(TAG, "showSession(): " + args);
showSession(args, 0);
} else {
Log.wtf(TAG, "**** Not starting MainInteractionService because" +
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java
index 2b28f0d..338c361 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java
@@ -16,24 +16,20 @@
package android.voiceinteraction.cts;
-import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.app.DirectAction;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteCallback;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.voiceinteraction.common.Utils;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
import com.android.compatibility.common.util.ThrowingRunnable;
-import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
@@ -42,6 +38,9 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/**
* Tests for the direction action related functions.
*/
@@ -52,16 +51,6 @@
private final @NonNull SessionControl mSessionControl = new SessionControl();
private final @NonNull ActivityControl mActivityControl = new ActivityControl();
- // TODO: move to super class
- @Before
- public void prepareDevice() throws Exception {
- // Unlock screen.
- runShellCommand("input keyevent KEYCODE_WAKEUP");
-
- // Dismiss keyguard, in case it's set as "Swipe to unlock".
- runShellCommand("wm dismiss-keyguard");
- }
-
@Test
public void testPerformDirectAction() throws Exception {
mActivityControl.startActivity();
@@ -86,6 +75,7 @@
}
}
+ @AppModeFull(reason = "testPerformDirectAction() is enough")
@Test
public void testCancelPerformedDirectAction() throws Exception {
mActivityControl.startActivity();
@@ -110,6 +100,7 @@
}
}
+ @AppModeFull(reason = "testPerformDirectAction() is enough")
@Test
public void testVoiceInteractorDestroy() throws Exception {
mActivityControl.startActivity();
@@ -127,6 +118,7 @@
}
}
+ @AppModeFull(reason = "testPerformDirectAction() is enough")
@Test
public void testNotifyDirectActionsChanged() throws Exception {
mActivityControl.startActivity();
@@ -255,11 +247,18 @@
latch.countDown();
});
- final Intent intent = new Intent();
- intent.setClassName("android.voiceinteraction.testapp",
- "android.voiceinteraction.testapp.DirectActionsActivity");
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(Utils.DIRECT_ACTIONS_KEY_CALLBACK, callback);
+ final Intent intent = new Intent()
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse("https://android.voiceinteraction.testapp"
+ + "/DirectActionsActivity"))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(Utils.DIRECT_ACTIONS_KEY_CALLBACK, callback);
+
+ if (!mContext.getPackageManager().isInstantApp()) {
+ intent.setPackage("android.voiceinteraction.testapp");
+ }
+
Log.v(TAG, "startActivity: " + intent);
mContext.startActivity(intent);
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/LocalVoiceInteractionTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/LocalVoiceInteractionTest.java
index 880ba90..fdbeb35 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/LocalVoiceInteractionTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/LocalVoiceInteractionTest.java
@@ -57,10 +57,7 @@
private void startTestActivity() throws Exception {
Intent intent = new Intent()
- .setAction(Intent.ACTION_VIEW)
- .addCategory(Intent.CATEGORY_BROWSABLE)
- .setData(Uri.parse("https://android.voiceinteraction.cts"
- + "TestLocalInteractionActivity"));
+ .setAction("android.intent.action.TEST_LOCAL_INTERACTION_ACTIVITY");
Log.i(TAG, "startTestActivity: " + intent);
mTestActivity = mActivityTestRule.launchActivity(intent);
}
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestStartActivity.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestStartActivity.java
index 11cedd9..b327f5d 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestStartActivity.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestStartActivity.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
-import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
index 2ea7e2f..fbb4836 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.voiceinteraction.common.Utils;
@@ -39,6 +40,9 @@
import androidx.test.rule.ActivityTestRule;
+// TODO: ideally we should split testAll() into multiple tests, and run at least one of them
+// on instant
+@AppModeFull(reason = "DirectActionsTest is enough")
public class VoiceInteractionTest extends AbstractVoiceInteractionTestCase {
static final String TAG = "VoiceInteractionTest";
private static final int TIMEOUT_MS = 20 * 1000;
diff --git a/tests/tests/voiceinteraction/testapp/AndroidManifest.xml b/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
index 4e7156b..c683c66 100644
--- a/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
@@ -25,15 +25,28 @@
android:label="Voice Interaction Test App"
android:theme="@android:style/Theme.DeviceDefault">
<intent-filter>
- <action android:name="android.intent.action.TEST_APP" />
+ <action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.VOICE" />
+ <data android:scheme="https" />
+ <data android:host="android.voiceinteraction.testapp" />
+ <data android:path="/TestApp" />
</intent-filter>
</activity>
<activity android:name=".DirectActionsActivity"
android:label="Direct actions activity"
android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="https" />
+ <data android:host="android.voiceinteraction.testapp" />
+ <data android:path="/DirectActionsActivity" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
</activity>
</application>
diff --git a/tests/tests/widget/AndroidTest.xml b/tests/tests/widget/AndroidTest.xml
index 123b9e7..fd9afe8 100644
--- a/tests/tests/widget/AndroidTest.xml
+++ b/tests/tests/widget/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsWidgetTestCases.apk" />
diff --git a/tools/cts-api-coverage/proto/cts_report.proto b/tools/cts-api-coverage/proto/cts_report.proto
index afb4338..5007c69 100644
--- a/tools/cts-api-coverage/proto/cts_report.proto
+++ b/tools/cts-api-coverage/proto/cts_report.proto
@@ -90,8 +90,12 @@
// The numbers are in dpi and should match android.util.DisplayMetrics.DENSITY_*
enum LogicalDensity {
LDPI = 120;
+ DENSITY_140 = 140;
MDPI = 160;
+ DENSITY_180 = 180;
+ DENSITY_200 = 200;
TVDPI = 213;
+ DENSITY_220 = 220;
HDPI = 240;
DENSITY_260 = 260;
DENSITY_280 = 280;
@@ -103,10 +107,12 @@
// DENSITY_XXHIGH (480 dpi).
DENSITY_400 = 400;
DENSITY_420 = 420;
+ DENSITY_440 = 440;
XXHDPI = 480;
// Intermediate density for screens that sit somewhere between DENSITY_XXHIGH (480 dpi) and
// DENSITY_XXXHIGH (640 dpi).
DENSITY_560 = 560;
+ DENSITY_600 = 600;
XXXHDPI = 640;
}
@@ -349,4 +355,4 @@
optional string abi = 6;
}
repeated TestPackage test_package = 8;
-}
\ No newline at end of file
+}