Merge "Fix testRestart" into rvc-dev
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
index bb27360..08ae77e 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
@@ -94,8 +94,12 @@
// Wait for the content provider to be updated.
try {
- blockedNumberLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+ if (!blockedNumberLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS)) {
+ Log.e(TAG, "Timed out waiting for blocked number update");
+ bundle.putBoolean(FAIL_EXTRA, true);
+ }
} catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting for blocked number update");
bundle.putBoolean(FAIL_EXTRA, true);
}
return bundle;
diff --git a/hostsidetests/appsecurity/OWNERS b/hostsidetests/appsecurity/OWNERS
index 166e7ef..6ad0c7a 100644
--- a/hostsidetests/appsecurity/OWNERS
+++ b/hostsidetests/appsecurity/OWNERS
@@ -13,8 +13,10 @@
per-file CorruptApkTests.java = rtmitchell@google.com
per-file DeviceIdentifierTest.java = cbrubaker@google.com
per-file DirectBootHostTest.java = jsharkey@google.com
-per-file DocumentsTestCase.java = jsharkey@google.com
-per-file DocumentsTest.java = jsharkey@google.com
+per-file DocumentsTestCase.java = dikshag@google.com
+per-file DocumentsTestCase.java = zemiao@google.com
+per-file DocumentsTest.java = dikshag@google.com
+per-file DocumentsTest.java = zemiao@google.com
per-file EphemeralTest.java = toddke@google.com
per-file ExternalStorageHostTest.java = jsharkey@google.com
per-file InstantAppUserTest.java = toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
index 9fe672b..8bdc594 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 95221
-jsharkey@google.com
+dikshag@google.com
+zemiao@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 03746fe..8aed0cf 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -360,6 +360,9 @@
public void testRestrictStorageAccessFrameworkEnabled_blockFromTree() throws Exception {
if (!supportedHardware()) return;
+ // Clear DocsUI's storage to avoid it opening stored last location.
+ clearDocumentsUi();
+
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
mActivity.startActivityForResult(intent, REQUEST_CODE);
@@ -368,11 +371,15 @@
// save button is disabled for the storage root
assertFalse(findSaveButton().isEnabled());
- findDocument("Download").click();
- mDevice.waitForIdle();
+ try {
+ findDocument("Download").click();
+ mDevice.waitForIdle();
- // save button is disabled for Download folder
- assertFalse(findSaveButton().isEnabled());
+ // save button is disabled for Download folder
+ assertFalse(findSaveButton().isEnabled());
+ } catch(UiObjectNotFoundException e) {
+ // It might be possible that Download directory does not exist.
+ }
findRoot("CtsCreate").click();
mDevice.waitForIdle();
@@ -388,7 +395,11 @@
}
public void testRestrictStorageAccessFrameworkDisabled_notBlockFromTree() throws Exception {
- if (!supportedHardware()) return;
+ if (!supportedHardware())
+ return;
+
+ // Clear DocsUI's storage to avoid it opening stored last location.
+ clearDocumentsUi();
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
mActivity.startActivityForResult(intent, REQUEST_CODE);
@@ -398,11 +409,15 @@
// save button is enabled for for the storage root
assertTrue(findSaveButton().isEnabled());
- findDocument("Download").click();
- mDevice.waitForIdle();
+ try {
+ findDocument("Download").click();
+ mDevice.waitForIdle();
- // save button is enabled for Download folder
- assertTrue(findSaveButton().isEnabled());
+ // save button is enabled for Download folder
+ assertTrue(findSaveButton().isEnabled());
+ } catch (UiObjectNotFoundException e) {
+ // It might be possible that Download directory does not exist.
+ }
findRoot("CtsCreate").click();
mDevice.waitForIdle();
@@ -646,8 +661,7 @@
public void testOpenDocumentAtInitialLocation() throws Exception {
if (!supportedHardware()) return;
- // Clear DocsUI's storage to avoid it opening stored last location
- // which may make this test pass "luckily".
+ // Clear DocsUI's storage to avoid it opening stored last location.
clearDocumentsUi();
final Uri docUri = DocumentsContract.buildDocumentUri(PROVIDER_PACKAGE, "doc:file1");
@@ -665,8 +679,7 @@
public void testOpenDocumentTreeAtInitialLocation() throws Exception {
if (!supportedHardware()) return;
- // Clear DocsUI's storage to avoid it opening stored last location
- // which may make this test pass "luckily".
+ // Clear DocsUI's storage to avoid it opening stored last location.
clearDocumentsUi();
final Uri docUri = DocumentsContract.buildDocumentUri(PROVIDER_PACKAGE, "doc:dir2");
@@ -682,8 +695,7 @@
public void testOpenDocumentTreeWithScopedStorage() throws Exception {
if (!supportedHardware()) return;
- // Clear DocsUI's storage to avoid it opening stored last location
- // which may make this test pass "luckily".
+ // Clear DocsUI's storage to avoid it opening stored last location.
clearDocumentsUi();
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
@@ -707,8 +719,7 @@
public void testOpenRootWithoutRootIdAtInitialLocation() throws Exception {
if (!supportedHardware()) return;
- // Clear DocsUI's storage to avoid it opening stored last location
- // which may make this test pass "luckily".
+ // Clear DocsUI's storage to avoid it opening stored last location.
clearDocumentsUi();
final Uri rootsUri = DocumentsContract.buildRootsUri(PROVIDER_PACKAGE);
@@ -724,8 +735,7 @@
public void testCreateDocumentAtInitialLocation() throws Exception {
if (!supportedHardware()) return;
- // Clear DocsUI's storage to avoid it opening stored last location
- // which may make this test pass "luckily".
+ // Clear DocsUI's storage to avoid it opening stored last location.
clearDocumentsUi();
final Uri treeUri = DocumentsContract.buildTreeDocumentUri(PROVIDER_PACKAGE, "doc:local");
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
index 6aa4553..339970a 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
@@ -89,6 +89,7 @@
EventActivation metric1Act1 =
MetricsUtils.createEventActivation(act1TtlSecs, act1MatcherId, act1CancelMatcherId)
+ .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
.build();
EventActivation metric1Act2 =
@@ -108,7 +109,6 @@
MetricActivation metric1Activation = MetricActivation.newBuilder()
.setMetricId(metric1Id)
- .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
.addEventActivation(metric1Act1)
.addEventActivation(metric1Act2)
.build();
@@ -403,13 +403,13 @@
* Metric 3: No activations; always active
**/
public void testMultipleActivations() throws Exception {
- final int act1TtlSecs = 100;
- final int act2TtlSecs = 200;
+ final int act1TtlSecs = 200;
+ final int act2TtlSecs = 400;
uploadConfig(createConfig(act1TtlSecs, act2TtlSecs));
// Trigger Metric 1 Activation 1 and Metric 2 Activation 1.
// Time remaining:
- // Metric 1 Activation 1: 100 seconds
+ // Metric 1 Activation 1: 200 seconds
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 0 seconds
@@ -422,7 +422,7 @@
logAllMetrics();
// Time remaining:
- // Metric 1 Activation 1: 50 seconds
+ // Metric 1 Activation 1: 100 seconds
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 0 seconds
@@ -435,7 +435,7 @@
// Trigger Metric 1 Activation 1 and Metric 2 Activation 1.
// Time remaining:
- // Metric 1 Activation 1: 100 seconds
+ // Metric 1 Activation 1: 200 seconds
// Metric 1 Activation 2: 0 seconds
// Metric 2 Activation 1: 0 seconds (will activate after boot)
// Metric 2 Activation 2: 0 seconds
@@ -448,9 +448,9 @@
logAllMetrics();
// Time remaining:
- // Metric 1 Activation 1: 100 seconds
+ // Metric 1 Activation 1: 200 seconds
// Metric 1 Activation 2: 0 seconds
- // Metric 2 Activation 1: 100 seconds
+ // Metric 2 Activation 1: 200 seconds
// Metric 2 Activation 2: 0 seconds
rebootDeviceAndWaitUntilReady();
@@ -461,9 +461,9 @@
// Trigger Metric 1 Activation 1 and Metric 2 Activation 1.
// Time remaining:
- // Metric 1 Activation 1: 100 seconds
+ // Metric 1 Activation 1: 200 seconds
// Metric 1 Activation 2: 0 seconds
- // Metric 2 Activation 1: 100 seconds
+ // Metric 2 Activation 1: 200 seconds
// Metric 2 Activation 2: 0 seconds
doAppBreadcrumbReported(act1MatcherId);
Thread.sleep(10L);
diff --git a/tests/BlobStore/AndroidManifest.xml b/tests/BlobStore/AndroidManifest.xml
index 8ffebfa..5efc390 100644
--- a/tests/BlobStore/AndroidManifest.xml
+++ b/tests/BlobStore/AndroidManifest.xml
@@ -17,7 +17,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.blob" >
- <application android:label="CtsBlobStoreTestCases">
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+
+ <application android:label="CtsBlobStoreTestCases"
+ android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/tests/BlobStore/AndroidTest.xml b/tests/BlobStore/AndroidTest.xml
index f74e2d6..45c066b 100644
--- a/tests/BlobStore/AndroidTest.xml
+++ b/tests/BlobStore/AndroidTest.xml
@@ -35,4 +35,9 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.cts.blob" />
</test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/CtsBlobStoreTestCases" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
</configuration>
diff --git a/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java b/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java
index a29fe58..362da8f 100644
--- a/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java
+++ b/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java
@@ -17,6 +17,7 @@
import static android.os.storage.StorageManager.UUID_DEFAULT;
+import static com.android.utils.blob.Utils.TAG;
import static com.android.utils.blob.Utils.writeToSession;
import static com.google.common.truth.Truth.assertThat;
@@ -34,6 +35,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.util.Log;
import com.android.cts.blob.ICommandReceiver;
import com.android.utils.blob.Utils;
@@ -64,6 +66,7 @@
session.allowPublicAccess();
}
+ Log.d(TAG, "Committing session: " + sessionId + "; blob: " + blobHandle);
final CompletableFuture<Integer> callback = new CompletableFuture<>();
session.commit(getMainExecutor(), callback::complete);
return callback.get(timeoutSec, TimeUnit.SECONDS);
diff --git a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
index bb86844..c7b47ad 100644
--- a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
+++ b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
@@ -76,12 +76,11 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import com.google.common.io.BaseEncoding;
-@RunWith(AndroidJUnit4.class)
+@RunWith(BlobStoreTestRunner.class)
public class BlobStoreManagerTest {
private static final long TIMEOUT_COMMIT_CALLBACK_SEC = 5;
@@ -222,10 +221,7 @@
blobData.readFromSessionAndVerifyBytes(session,
202 /* offset */, 2002 /* length */);
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
+ commitSession(sessionId, session, blobData.getBlobHandle());
}
} finally {
blobData.delete();
@@ -597,10 +593,7 @@
assertThat(pfd).isNotNull();
blobData.writeToFd(pfd.getFileDescriptor(), 0 /* offset */, 100 /* length */);
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
+ commitSession(sessionId, session, blobData.getBlobHandle());
// Verify that writing to the session after commit will throw.
assertThrows(IOException.class, () -> blobData.writeToFd(
@@ -623,10 +616,8 @@
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
blobData.writeToSession(session, 0, blobData.getFileSize() - 2);
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(1);
+ commitSession(sessionId, session, blobData.getBlobHandle(),
+ false /* expectSuccess */);
}
} finally {
blobData.delete();
@@ -648,10 +639,8 @@
out.write("wrong_data".getBytes(StandardCharsets.UTF_8));
}
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(1);
+ commitSession(sessionId, session, blobData.getBlobHandle(),
+ false /* expectSuccess */);
}
} finally {
blobData.delete();
@@ -723,6 +712,8 @@
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
blobData.writeToSession(session);
+ Log.d(TAG, "Committing session: " + sessionId
+ + "; blob: " + blobData.getBlobHandle());
final CompletableFuture<Integer> callback = new CompletableFuture<>();
session.commit(mContext.getMainExecutor(), callback::complete);
assertThat(callback.get(commitTimeoutSec, TimeUnit.SECONDS))
@@ -804,10 +795,7 @@
blobData.readFromSessionAndVerifyBytes(session, partialFileSizeBytes,
(int) (blobData.getFileSize() - partialFileSizeBytes));
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
+ commitSession(sessionId, session, blobData.getBlobHandle());
}
// Verify that blob can be accessed after committing.
@@ -849,10 +837,7 @@
assertThrows(SecurityException.class,
() -> mBlobStoreManager.openBlob(blobData.getBlobHandle()));
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
+ commitSession(sessionId, session, blobData.getBlobHandle());
}
// Verify that blob can be accessed after committing.
@@ -1066,10 +1051,7 @@
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
blobData.writeToSession(session, partialFileSize,
session.getSize() - partialFileSize, blobData.getFileSize());
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
+ commitSession(sessionId, session, blobData.getBlobHandle());
}
acquireLease(mContext, blobData.getBlobHandle(), R.string.test_desc);
@@ -1119,10 +1101,7 @@
blobData.writeToSession(session);
session.allowPublicAccess();
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
+ commitSession(sessionId, session, blobData.getBlobHandle());
}
StorageStats afterStatsForPkg = storageStatsManager
@@ -1481,10 +1460,7 @@
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
blobData.writeToSession(session, partialFileSize,
blobData.getFileSize() - partialFileSize, blobData.getFileSize());
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
+ commitSession(sessionId, session, blobData.getBlobHandle());
}
}
@@ -1552,8 +1528,8 @@
final DummyBlobData blobData2 = new DummyBlobData.Builder(mContext).build();
blobData2.prepare();
- commitBlob(blobData1, null /* accessModifier */, 0 /* expectedResult */);
- commitBlob(blobData2, null /* accessModifier */, 1 /* expectedResult */);
+ commitBlob(blobData1, null /* accessModifier */, true /* expectSuccess */);
+ commitBlob(blobData2, null /* accessModifier */, false /* expectSuccess */);
}, Pair.create(KEY_MAX_COMMITTED_BLOBS, String.valueOf(1)));
}
@@ -1738,11 +1714,11 @@
private long commitBlob(DummyBlobData blobData,
AccessModifier accessModifier) throws Exception {
- return commitBlob(blobData, accessModifier, 0 /* expectedResult */);
+ return commitBlob(blobData, accessModifier, true /* expectSuccess */);
}
private long commitBlob(DummyBlobData blobData,
- AccessModifier accessModifier, int expectedResult) throws Exception {
+ AccessModifier accessModifier, boolean expectSuccess) throws Exception {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
@@ -1751,14 +1727,29 @@
if (accessModifier != null) {
accessModifier.modify(session);
}
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(expectedResult);
+ commitSession(sessionId, session, blobData.getBlobHandle(), expectSuccess);
}
return sessionId;
}
+ private void commitSession(long sessionId, BlobStoreManager.Session session,
+ BlobHandle blobHandle) throws Exception {
+ commitSession(sessionId, session, blobHandle, true /* expectSuccess */);
+ }
+
+ private void commitSession(long sessionId, BlobStoreManager.Session session,
+ BlobHandle blobHandle, boolean expectSuccess) throws Exception {
+ Log.d(TAG, "Committing session: " + sessionId + "; blob: " + blobHandle);
+ final CompletableFuture<Integer> callback = new CompletableFuture<>();
+ session.commit(mContext.getMainExecutor(), callback::complete);
+ final int result = callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS);
+ if (expectSuccess) {
+ assertThat(result).isEqualTo(0);
+ } else {
+ assertThat(result).isNotEqualTo(0);
+ }
+ }
+
private interface AccessModifier {
void modify(BlobStoreManager.Session session) throws Exception;
}
diff --git a/tests/BlobStore/src/com/android/cts/blob/BlobStoreTestRunner.java b/tests/BlobStore/src/com/android/cts/blob/BlobStoreTestRunner.java
new file mode 100644
index 0000000..4b95573
--- /dev/null
+++ b/tests/BlobStore/src/com/android/cts/blob/BlobStoreTestRunner.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.blob;
+
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+
+import org.junit.rules.RunRules;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+import java.util.List;
+
+/**
+ * Custom runner to allow dumping logs after a test failure before the @After methods get to run.
+ */
+public class BlobStoreTestRunner extends AndroidJUnit4ClassRunner {
+ private TestRule mDumpOnFailureRule = new DumpOnFailureRule();
+
+ public BlobStoreTestRunner(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+
+ @Override
+ public Statement methodInvoker(FrameworkMethod method, Object test) {
+ return new RunRules(super.methodInvoker(method, test), List.of(mDumpOnFailureRule),
+ describeChild(method));
+ }
+}
diff --git a/tests/BlobStore/src/com/android/cts/blob/DumpOnFailureRule.java b/tests/BlobStore/src/com/android/cts/blob/DumpOnFailureRule.java
new file mode 100644
index 0000000..02ac5d3
--- /dev/null
+++ b/tests/BlobStore/src/com/android/cts/blob/DumpOnFailureRule.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.blob;
+
+import static com.android.utils.blob.Utils.TAG;
+
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.compatibility.common.util.OnFailureRule;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+public class DumpOnFailureRule extends OnFailureRule {
+ private File mDumpDir = new File(Environment.getExternalStorageDirectory(),
+ "CtsBlobStoreTestCases");
+
+ @Override
+ public void onTestFailure(Statement base, Description description, Throwable throwable) {
+ final String testName = description.getClassName() + "_" + description.getMethodName();
+
+ if (throwable instanceof AssumptionViolatedException) {
+ Log.d(TAG, "Skipping test " + testName + ": " + throwable);
+ return;
+ }
+
+ prepareDumpRootDir();
+ final File dumpFile = new File(mDumpDir, "dump-" + testName);
+ Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath());
+ try (FileOutputStream out = new FileOutputStream(dumpFile)) {
+ dumpCommandOutput(out, "dumpsys blob_store");
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Error opening file: " + dumpFile, e);
+ } catch (IOException e) {
+ Log.e(TAG, "Error closing file: " + dumpFile, e);
+ }
+ }
+
+ void dumpCommandOutput(FileOutputStream out, String cmd) {
+ final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation().executeShellCommand(cmd);
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8));
+ FileUtils.copy(in, out);
+ out.write("\n\n=================================================================\n\n"
+ .getBytes(StandardCharsets.UTF_8));
+ } catch (IOException e) {
+ Log.e(TAG, "Error dumping '" + cmd + "'", e);
+ }
+ }
+
+ void prepareDumpRootDir() {
+ if (!mDumpDir.exists() && !mDumpDir.mkdir()) {
+ Log.e(TAG, "Error creating " + mDumpDir);
+ }
+ }
+}
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 5f60ea4..aabcc6b 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -380,6 +380,7 @@
android:screenOrientation="locked"
android:turnScreenOn="true"
android:showWhenLocked="true"
+ android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="WindowCtsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -404,6 +405,9 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity android:name="android.server.wm.WindowInputTests$TestActivity" />
+
<service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService"
android:foregroundServiceType="mediaProjection"
android:enabled="true">
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java
index 97377bf..e305784 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java
@@ -17,6 +17,7 @@
package android.server.wm;
import android.app.Activity;
+import android.graphics.Insets;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
@@ -70,6 +71,16 @@
return findViewById(R.id.listview_window);
}
+ public Insets getAppliedInsets() {
+ View view = (View) getContentView().getParent();
+ int[] location = new int[2];
+ view.getLocationInWindow(location);
+ View decorView = getWindow().getDecorView();
+ return Insets.of(location[0], location[1],
+ decorView.getWidth() - (location[0] + view.getWidth()),
+ decorView.getHeight() - (location[1] + view.getHeight()));
+ }
+
public WindowInsets getLastInsets() {
return mLastInsets;
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
index 390de30..2ee8841 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
@@ -19,16 +19,29 @@
import static android.server.wm.ActivityManagerTestBase.launchHomeActivityNoWait;
import static android.server.wm.UiDeviceUtils.pressUnlockButton;
import static android.server.wm.UiDeviceUtils.pressWakeupButton;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.Activity;
import android.app.Instrumentation;
+import android.content.ContentResolver;
+import android.content.Intent;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+import android.server.wm.settings.SettingsSession;
import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -36,11 +49,16 @@
import androidx.test.rule.ActivityTestRule;
import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.SystemUtil;
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
/**
* Ensure moving windows and tapping is done synchronously.
@@ -48,12 +66,14 @@
* Build/Install/Run:
* atest CtsWindowManagerDeviceTestCases:WindowInputTests
*/
+@Presubmit
public class WindowInputTests {
private final int TOTAL_NUMBER_OF_CLICKS = 100;
- private final ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+ private final ActivityTestRule<TestActivity> mActivityRule =
+ new ActivityTestRule<>(TestActivity.class);
private Instrumentation mInstrumentation;
- private Activity mActivity;
+ private TestActivity mActivity;
private View mView;
private final Random mRandom = new Random();
@@ -89,7 +109,7 @@
mView.setOnClickListener((v) -> {
mClickCount++;
});
- wm.addView(mView, p);
+ mActivity.addWindow(mView, p);
});
mInstrumentation.waitForIdleSync();
@@ -121,4 +141,195 @@
int randomY = mRandom.nextInt(bounds.bottom - bounds.top) + bounds.top;
outLocation.set(randomX, randomY);
}
+
+ @Test
+ public void testFilterTouchesWhenObscured() throws Throwable {
+ final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
+ mClickCount = 0;
+
+ // Set up window.
+ mActivityRule.runOnUiThread(() -> {
+ mView = new View(mActivity);
+ p.width = 20;
+ p.height = 20;
+ p.gravity = Gravity.LEFT | Gravity.TOP;
+ mView.setFilterTouchesWhenObscured(true);
+ mView.setOnClickListener((v) -> {
+ mClickCount++;
+ });
+ mActivity.addWindow(mView, p);
+
+ View viewOverlap = new View(mActivity);
+ p.gravity = Gravity.RIGHT | Gravity.TOP;
+ p.type = WindowManager.LayoutParams.TYPE_APPLICATION;
+ mActivity.addWindow(viewOverlap, p);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mView);
+ assertEquals(0, mClickCount);
+ }
+
+ @Test
+ public void testOverlapWindow() throws Throwable {
+ final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
+ mClickCount = 0;
+ try (final PointerLocationSession session = new PointerLocationSession()) {
+ session.set(true);
+ // Set up window.
+ mActivityRule.runOnUiThread(() -> {
+ mView = new View(mActivity);
+ p.width = 20;
+ p.height = 20;
+ p.gravity = Gravity.LEFT | Gravity.TOP;
+ mView.setFilterTouchesWhenObscured(true);
+ mView.setOnClickListener((v) -> {
+ mClickCount++;
+ });
+ mActivity.addWindow(mView, p);
+
+ });
+ mInstrumentation.waitForIdleSync();
+
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mView);
+ }
+ assertEquals(1, mClickCount);
+ }
+
+ @Test
+ public void testWindowBecomesUnTouchable() throws Throwable {
+ final WindowManager wm = mActivity.getWindowManager();
+ final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
+ mClickCount = 0;
+
+ final View viewOverlap = new View(mActivity);
+
+ // Set up window.
+ mActivityRule.runOnUiThread(() -> {
+ mView = new View(mActivity);
+ p.width = 20;
+ p.height = 20;
+ p.gravity = Gravity.LEFT | Gravity.TOP;
+ mView.setOnClickListener((v) -> {
+ mClickCount++;
+ });
+ mActivity.addWindow(mView, p);
+
+ p.width = 100;
+ p.height = 100;
+ p.gravity = Gravity.LEFT | Gravity.TOP;
+ p.type = WindowManager.LayoutParams.TYPE_APPLICATION;
+ mActivity.addWindow(viewOverlap, p);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mView);
+ assertEquals(0, mClickCount);
+
+ mActivityRule.runOnUiThread(() -> {
+ p.flags = FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE;
+ wm.updateViewLayout(viewOverlap, p);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mView);
+ assertEquals(1, mClickCount);
+ }
+
+ @Test
+ public void testInjectToStatusBar() {
+ // Try to inject event to status bar.
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent eventHover = MotionEvent.obtain(
+ downTime, downTime, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+ eventHover.setSource(InputDevice.SOURCE_MOUSE);
+ try {
+ mInstrumentation.sendPointerSync(eventHover);
+ fail("Not allowed to inject event to the window from another process.");
+ } catch (SecurityException e) {
+ // Should not be allowed to inject event to the window from another process.
+ }
+ }
+
+ @Test
+ public void testInjectFromThread() throws InterruptedException {
+ // Continually inject event to activity from thread.
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent eventDown = MotionEvent.obtain(
+ downTime, downTime, MotionEvent.ACTION_DOWN, 100, 100, 1);
+ mInstrumentation.sendPointerSync(eventDown);
+
+ final ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(() -> {
+ mInstrumentation.sendPointerSync(eventDown);
+ for (int i = 0; i < 20; i++) {
+ final long eventTime = SystemClock.uptimeMillis();
+ final MotionEvent eventMove = MotionEvent.obtain(
+ downTime, eventTime, MotionEvent.ACTION_MOVE, 100, 100, 1);
+ try {
+ mInstrumentation.sendPointerSync(eventMove);
+ } catch (SecurityException e) {
+ fail("Should be allowed to inject event.");
+ }
+ }
+ });
+
+ // Launch another activity, should not crash the process.
+ final Intent intent = new Intent(mActivity, TestActivity.class);
+ mActivityRule.launchActivity(intent);
+ mInstrumentation.waitForIdleSync();
+
+ executor.shutdown();
+ executor.awaitTermination(5L, TimeUnit.SECONDS);
+ }
+
+ public static class TestActivity extends Activity {
+ private ArrayList<View> mViews = new ArrayList<>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ void addWindow(View view, WindowManager.LayoutParams attrs) {
+ getWindowManager().addView(view, attrs);
+ mViews.add(view);
+ }
+
+ void removeAllWindows() {
+ for (View view : mViews) {
+ getWindowManager().removeViewImmediate(view);
+ }
+ mViews.clear();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ removeAllWindows();
+ }
+ }
+
+ /** Helper class to save, set, and restore pointer location preferences. */
+ private static class PointerLocationSession extends SettingsSession<Boolean> {
+ PointerLocationSession() {
+ super(Settings.System.getUriFor("pointer_location" /* POINTER_LOCATION */),
+ PointerLocationSession::get,
+ PointerLocationSession::put);
+ }
+
+ private static void put(ContentResolver contentResolver, String s, boolean v) {
+ SystemUtil.runShellCommand(
+ "settings put system " + "pointer_location" + " " + (v ? 1 : 0));
+ }
+
+ private static boolean get(ContentResolver contentResolver, String s) {
+ try {
+ return Integer.parseInt(SystemUtil.runShellCommand(
+ "settings get system " + "pointer_location").trim()) == 1;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationImeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationImeTests.java
index 3668172..54dbf56 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationImeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationImeTests.java
@@ -93,9 +93,9 @@
@Test
@FlakyTest(detail = "Promote once confirmed non-flaky")
public void testAnimationCallbacks_overlapping_opposite() throws Exception {
- assumeTrue(hasWindowInsets(navigationBars()));
-
initActivity(false /* useFloating */);
+ assumeTrue(hasWindowInsets(mRootView, navigationBars()));
+
WindowInsets before = mActivity.mLastWindowInsets;
MultiAnimCallback callbackInner = new MultiAnimCallback();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
index ebcc34a..13f8c59 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
@@ -104,8 +104,8 @@
assertEquals(after, steps.get(steps.size() - 1).insets);
}
- protected boolean hasWindowInsets(int types) {
- return Insets.NONE != mRootView.getRootWindowInsets().getInsetsIgnoringVisibility(types);
+ protected static boolean hasWindowInsets(View rootView, int types) {
+ return Insets.NONE != rootView.getRootWindowInsets().getInsetsIgnoringVisibility(types);
}
protected void assertAnimationSteps(ArrayList<AnimationStep> steps, boolean showAnimation) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
index 0a471a6..6bc9070 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
@@ -65,7 +65,7 @@
super.setUp();
mActivity = startActivity(TestActivity.class);
mRootView = mActivity.getWindow().getDecorView();
- assumeTrue(hasWindowInsets(systemBars()));
+ assumeTrue(hasWindowInsets(mRootView, systemBars()));
}
@Test
@@ -219,11 +219,11 @@
waitForOrFail("Waiting until animation done", () -> done[0]);
- if (hasWindowInsets(statusBars())) {
+ if (hasWindowInsets(mRootView, statusBars())) {
verify(childCallback).onStart(any(), argThat(
bounds -> bounds.getUpperBound().equals(before.getInsets(statusBars()))));
}
- if (hasWindowInsets(navigationBars())) {
+ if (hasWindowInsets(mRootView, navigationBars())) {
verify(childCallback, atLeastOnce()).onProgress(argThat(
insets -> NONE.equals(insets.getInsets(navigationBars()))), any());
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java
index baef606..ee80068 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java
@@ -18,6 +18,7 @@
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -37,6 +38,7 @@
import android.app.Instrumentation;
import android.app.Presentation;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
@@ -661,6 +663,21 @@
}
@Test
+ public void testSetFitsContentForInsets_displayCutoutInsets_areApplied()
+ throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ mWindow.setDecorFitsSystemWindows(true);
+ WindowManager.LayoutParams attrs = mWindow.getAttributes();
+ attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mWindow.setAttributes(attrs);
+ });
+ mInstrumentation.waitForIdleSync();
+ assertEquals(mActivity.getContentView().getRootWindowInsets().getSystemWindowInsets(),
+ mActivity.getAppliedInsets());
+ }
+
+ @Test
public void testSetFitsContentForInsets_defaultLegacy_none()
throws Throwable {
mInstrumentation.waitForIdleSync();
diff --git a/tests/tests/appenumeration/AndroidTest.xml b/tests/tests/appenumeration/AndroidTest.xml
index 5e210f1..06f5ae4 100644
--- a/tests/tests/appenumeration/AndroidTest.xml
+++ b/tests/tests/appenumeration/AndroidTest.xml
@@ -33,6 +33,8 @@
<option name="test-file-name" value="CtsAppEnumerationDocumentsActivityTarget.apk" />
<option name="test-file-name" value="CtsAppEnumerationShareActivityTarget.apk" />
<option name="test-file-name" value="CtsAppEnumerationWebActivityTarget.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationBrowserActivityTarget.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationBrowserWildcardActivityTarget.apk" />
<option name="test-file-name" value="CtsAppEnumerationSharedUidSource.apk" />
<option name="test-file-name" value="CtsAppEnumerationSharedUidTarget.apk" />
<option name="test-file-name" value="CtsAppEnumerationQueriesNothing.apk" />
@@ -54,6 +56,7 @@
<option name="test-file-name" value="CtsAppEnumerationWildcardDocumentEditorActivitySource.apk" />
<option name="test-file-name" value="CtsAppEnumerationWildcardShareActivitySource.apk" />
<option name="test-file-name" value="CtsAppEnumerationWildcardWebActivitySource.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationWildcardBrowserActivitySource.apk" />
</target_preparer>
<!-- Create place to store apks -->
diff --git a/tests/tests/appenumeration/app/source/Android.bp b/tests/tests/appenumeration/app/source/Android.bp
index d7832c4..a3765dd 100644
--- a/tests/tests/appenumeration/app/source/Android.bp
+++ b/tests/tests/appenumeration/app/source/Android.bp
@@ -269,3 +269,16 @@
"general-tests",
],
}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationWildcardBrowserActivitySource",
+ manifest: "AndroidManifest-queriesWildcard-browserActivity.xml",
+ defaults: ["CtsAppEnumerationQueriesDefaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+}
+
diff --git a/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-browserActivity.xml b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-browserActivity.xml
new file mode 100644
index 0000000..b6f96aa
--- /dev/null
+++ b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-browserActivity.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ - Copyright (C) 2020 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.appenumeration.queries.wildcard.browser">
+
+ <queries>
+ <intent>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" />
+ </intent>
+ <intent>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="https" />
+ </intent>
+ </queries>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.cts.query.TestActivity"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/target/Android.bp b/tests/tests/appenumeration/app/target/Android.bp
index d34e9e1..04ebc78 100644
--- a/tests/tests/appenumeration/app/target/Android.bp
+++ b/tests/tests/appenumeration/app/target/Android.bp
@@ -123,3 +123,31 @@
],
sdk_version: "test_current",
}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationBrowserActivityTarget",
+ manifest: "AndroidManifest-browserActivity.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationBrowserWildcardActivityTarget",
+ manifest: "AndroidManifest-browserWildcardActivity.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-browserActivity.xml b/tests/tests/appenumeration/app/target/AndroidManifest-browserActivity.xml
new file mode 100644
index 0000000..696ef30
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-browserActivity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ - Copyright (C) 2020 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.appenumeration.browser.activity">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.WebBrowser">
+ <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="http" />
+ <data android:scheme="https" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-browserWildcardActivity.xml b/tests/tests/appenumeration/app/target/AndroidManifest-browserWildcardActivity.xml
new file mode 100644
index 0000000..60ced57
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-browserWildcardActivity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ - Copyright (C) 2020 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.appenumeration.browser.wildcard.activity">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.WebBrowser">
+ <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="http" host="*"/>
+ <data android:scheme="https" host-="*"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
index aea7db5..c8c225c 100644
--- a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
+++ b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
@@ -66,6 +66,8 @@
public static final String QUERIES_WILDCARD_SHARE = PKG_BASE + "queries.wildcard.share";
/** A package that queries for all web intent browsable targets. */
public static final String QUERIES_WILDCARD_WEB = PKG_BASE + "queries.wildcard.web";
+ /** A package that queries for only browser intent targets. */
+ public static final String QUERIES_WILDCARD_BROWSER = PKG_BASE + "queries.wildcard.browser";
/** A package that queries for {@link #TARGET_NO_API} package */
public static final String TARGET_SHARED_USER = PKG_BASE + "noapi.shareduid";
@@ -83,6 +85,10 @@
public static final String TARGET_SHARE = PKG_BASE + "share.activity";
/** A package that offers an activity that handles browsable web intents for a specific host */
public static final String TARGET_WEB = PKG_BASE + "web.activity";
+ /** A package that offers an activity acts as a browser with host undefined */
+ public static final String TARGET_BROWSER = PKG_BASE + "browser.activity";
+ /** A package that offers an activity acts as a browser, but uses a wildcard for host */
+ public static final String TARGET_BROWSER_WILDCARD = PKG_BASE + "browser.wildcard.activity";
private static final String BASE_PATH = "/data/local/tmp/cts/appenumeration/";
public static final String TARGET_NO_API_APK = BASE_PATH + "CtsAppEnumerationNoApi.apk";
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index b63a1c4..78c8570 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -51,10 +51,13 @@
import static android.appenumeration.cts.Constants.QUERIES_UNEXPORTED_SERVICE_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_BROWSABLE;
+import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_BROWSER;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_CONTACTS;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_EDITOR;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_SHARE;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_WEB;
+import static android.appenumeration.cts.Constants.TARGET_BROWSER;
+import static android.appenumeration.cts.Constants.TARGET_BROWSER_WILDCARD;
import static android.appenumeration.cts.Constants.TARGET_CONTACTS;
import static android.appenumeration.cts.Constants.TARGET_EDITOR;
import static android.appenumeration.cts.Constants.TARGET_FILTERS;
@@ -384,6 +387,15 @@
}
@Test
+ public void queriesWildcardBrowser() throws Exception {
+ assertNotVisible(QUERIES_NOTHING, TARGET_BROWSER);
+ assertNotVisible(QUERIES_WILDCARD_BROWSER, TARGET_WEB);
+ assertVisible(QUERIES_WILDCARD_BROWSER, TARGET_BROWSER);
+ assertVisible(QUERIES_WILDCARD_BROWSER, TARGET_BROWSER_WILDCARD);
+ }
+
+
+ @Test
public void queriesWildcardEditor() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_EDITOR);
assertVisible(QUERIES_WILDCARD_EDITOR, TARGET_EDITOR);
diff --git a/tests/tests/content/src/android/content/cts/IntentFilterTest.java b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
index 757f4bd..9888891 100644
--- a/tests/tests/content/src/android/content/cts/IntentFilterTest.java
+++ b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
@@ -16,9 +16,11 @@
package android.content.cts;
+import static android.content.IntentFilter.MATCH_ADJUSTMENT_NORMAL;
import static android.content.IntentFilter.MATCH_CATEGORY_HOST;
import static android.content.IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART;
import static android.content.IntentFilter.MATCH_CATEGORY_TYPE;
+import static android.content.IntentFilter.NO_MATCH_DATA;
import static android.os.PatternMatcher.PATTERN_LITERAL;
import static android.os.PatternMatcher.PATTERN_PREFIX;
import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
@@ -937,6 +939,54 @@
true));
}
+ public void testAppEnumerationBrowser() throws Exception {
+ IntentFilter appWithWebLink = new Match(
+ new String[]{Intent.ACTION_VIEW},
+ new String[]{Intent.CATEGORY_BROWSABLE},
+ null,
+ new String[]{"http", "https"},
+ new String[]{"some.app.domain"},
+ null);
+
+ IntentFilter browserFilterWithWildcard = new Match(
+ new String[]{Intent.ACTION_VIEW},
+ new String[]{Intent.CATEGORY_BROWSABLE},
+ null,
+ new String[]{"http", "https"},
+ new String[]{"*"},
+ null);
+
+ IntentFilter browserFilterWithoutWildcard = new Match(
+ new String[]{Intent.ACTION_VIEW},
+ new String[]{Intent.CATEGORY_BROWSABLE},
+ null,
+ new String[]{"http", "https"},
+ null,
+ null);
+
+ checkMatches(browserFilterWithWildcard,
+ new MatchCondition(MATCH_CATEGORY_HOST,
+ Intent.ACTION_VIEW,
+ new String[]{Intent.CATEGORY_BROWSABLE},
+ null,
+ "https://",
+ true));
+ checkMatches(browserFilterWithoutWildcard,
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME | MATCH_ADJUSTMENT_NORMAL,
+ Intent.ACTION_VIEW,
+ new String[]{Intent.CATEGORY_BROWSABLE},
+ null,
+ "https://",
+ true));
+ checkMatches(appWithWebLink,
+ new MatchCondition(NO_MATCH_DATA,
+ Intent.ACTION_VIEW,
+ new String[]{Intent.CATEGORY_BROWSABLE},
+ null,
+ "https://",
+ true));
+ }
+
public void testWriteToXml() throws IllegalArgumentException, IllegalStateException,
IOException, MalformedMimeTypeException, XmlPullParserException {
XmlSerializer xml;
diff --git a/tests/tests/media/res/raw/tags.mp4 b/tests/tests/media/res/raw/tags.mp4
new file mode 100644
index 0000000..4e7dc43
--- /dev/null
+++ b/tests/tests/media/res/raw/tags.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
index 48208d9..79a6818 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
@@ -380,6 +380,31 @@
mRetriever.getEmbeddedPicture());
}
+ public void testMp4Metadata() {
+ setDataSourceFd(R.raw.tags);
+ assertEquals("Wrong title",
+ "the title",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
+ assertEquals("Wrong artist",
+ "the artist",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
+ assertEquals("Wrong album",
+ "the album",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
+ assertEquals("Wrong album artist",
+ "the album artist",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST));
+ assertEquals("Wrong composer",
+ "the composer",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER));
+ assertEquals("Wrong genre",
+ "custom genre",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
+ assertEquals("Wrong year",
+ "2020",
+ mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR));
+ }
+
public void testMp4AlbumArt() {
setDataSourceFd(R.raw.swirl_128x128_h264_albumart);
assertEquals("Mime type was other than expected",
diff --git a/tests/tests/os/CtsOsTestCases.xml b/tests/tests/os/CtsOsTestCases.xml
index 7ce85d6..193eb0f 100644
--- a/tests/tests/os/CtsOsTestCases.xml
+++ b/tests/tests/os/CtsOsTestCases.xml
@@ -28,6 +28,7 @@
<option name="test-file-name" value="CtsMockInputMethod.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" />
<option name="screen-always-on" value="on" />
</target_preparer>
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 9bebccf..357e9c7 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -272,6 +272,8 @@
) {
installApp(apk)
try {
+ // Try to reduce flakiness caused by new package update not propagating in time
+ Thread.sleep(1000)
action()
} finally {
uninstallApp(packageName)
diff --git a/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml b/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml
index 171d331..ab2ef79 100644
--- a/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml
+++ b/tests/tests/permission/AppThatDefinesUndefinedPermissionGroupElement/AndroidManifest.xml
@@ -31,7 +31,8 @@
<application android:label="CtsPermissionUnknownGroup">
<activity
android:name=".RequestPermissions"
- android:exported="true"/>
+ android:exported="true"
+ android:visibleToInstantApps="true"/>
</application>
</manifest>
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 8185462..e6a9c05 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -382,6 +382,7 @@
Uri blockedUri = null;
try {
+ TestUtils.executeShellCommand(getInstrumentation(), "telecom stop-block-suppression");
Uri testNumberUri = createTestNumber();
blockedUri = blockNumber(testNumberUri);
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index ebdbf89..5815aed 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -27,6 +27,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.test.InstrumentationTestCase;
+import android.text.TextUtils;
import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -113,6 +114,10 @@
if (!TestUtils.shouldTestTelecom(mContext)) {
return;
}
+ // We do not expect CTS to be the default dialer, since it confers some permissions that we
+ // explicitly assume that we don't hold during testing.
+ TestUtils.setDefaultDialer(getInstrumentation(), "");
+
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
mPhoneAccountRegisteredLatch = new TestUtils.InvokeCounter("registerPhoneAcct");
mPhoneAccountUnRegisteredLatch = new TestUtils.InvokeCounter("unRegisterPhoneAcct");
@@ -127,6 +132,7 @@
PhoneAccount retrievedPhoneAccount = mTelecomManager.getPhoneAccount(
TEST_PHONE_ACCOUNT_HANDLE);
assertNull("Test account not deregistered.", retrievedPhoneAccount);
+
super.tearDown();
}