Merge "Add extra connection check on testAutoFillOneDatasetAndSave()" into oc-dev
am: 8c3b60f139
Change-Id: If92a78c9d40136d443d06957bab3d4224d3514a1
diff --git a/common/util/src/com/android/compatibility/common/util/VendorInterfaceTest.java b/common/util/src/com/android/compatibility/common/util/VendorInterfaceTest.java
index 5bcaf0c..5a448f1 100644
--- a/common/util/src/com/android/compatibility/common/util/VendorInterfaceTest.java
+++ b/common/util/src/com/android/compatibility/common/util/VendorInterfaceTest.java
@@ -26,8 +26,7 @@
* AOSP requirement.
* <p>
* Test classes and test cases marked with this annotation will be included in the
- * cts-vendor-interface plan
- * by default.
+ * cts-vendor-interface plan by default.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
index 31f82ac..53417e4 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
@@ -149,6 +149,7 @@
final String logSeparator = clearLogcat();
launchActivityInDockStack(LAUNCHING_ACTIVITY);
+
getLaunchActivityBuilder().setToSide(true).setTargetActivityName(RESIZEABLE_ACTIVITY_NAME)
.execute();
final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
diff --git a/hostsidetests/tzdata/Android.mk b/hostsidetests/tzdata/Android.mk
new file mode 100644
index 0000000..6eab01c
--- /dev/null
+++ b/hostsidetests/tzdata/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := CtsHostTzDataTests
+
+LOCAL_JAVA_LIBRARIES := tradefed
+
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata-testing-host tzdata_shared2-host tzdata_tools2-host
+
+LOCAL_CTS_TEST_PACKAGE := android.host.tzdata
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/tzdata/AndroidTest.xml b/hostsidetests/tzdata/AndroidTest.xml
new file mode 100644
index 0000000..cccfe5a
--- /dev/null
+++ b/hostsidetests/tzdata/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for CTS tzdatacheck host test cases">
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsHostTzDataTests.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
new file mode 100644
index 0000000..c059e89
--- /dev/null
+++ b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
@@ -0,0 +1,976 @@
+/*
+ * Copyright (C) 2017 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.tzdata;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.StringJoiner;
+import java.util.function.Consumer;
+import libcore.tzdata.shared2.DistroVersion;
+import libcore.tzdata.shared2.TimeZoneDistro;
+import libcore.tzdata.testing.ZoneInfoTestHelper;
+import libcore.tzdata.update2.tools.TimeZoneDistroBuilder;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * Tests for the tzdatacheck binary.
+ *
+ * <p>The tzdatacheck binary operates over two directories: the "system directory" containing the
+ * time zone rules in the system image, and a "data directory" in the data partition which can
+ * optionally contain time zone rules data files for bionic/libcore and ICU.
+ *
+ * <p>This test executes the tzdatacheck binary to confirm it operates correctly in a number of
+ * simulated situations; simulated system and data directories in various states are created in a
+ * location the shell user has permission to access and the tzdatacheck binary is then executed.
+ * The status code and directory state after execution is then used to determine if the tzdatacheck
+ * binary operated correctly.
+ *
+ * <p>Most of the tests below prepare simulated directory structure for the system and data dirs
+ * on the host before pushing them to the device. Device state is then checked rather than syncing
+ * the files back.
+ */
+public class TzDataCheckTest extends DeviceTestCase {
+
+ /**
+ * The name of the directory containing the current time zone rules data beneath
+ * {@link #mDataDir}. Also known to {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and
+ * tzdatacheck.cpp.
+ */
+ private static final String CURRENT_DIR_NAME = "current";
+
+ /**
+ * The name of the directory containing the staged time zone rules data beneath
+ * {@link #mDataDir}. Also known to {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and
+ * tzdatacheck.cpp.
+ */
+ private static final String STAGED_DIR_NAME = "staged";
+
+ /**
+ * The name of the file inside the staged directory that indicates the staged operation is an
+ * uninstall. Also known to {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and
+ * tzdatacheck.cpp.
+ */
+ private static final String UNINSTALL_TOMBSTONE_FILE_NAME = "STAGED_UNINSTALL_TOMBSTONE";
+
+ /**
+ * The name of the /system time zone data file. Also known to
+ * {@link libcore.tzdata.update2.TimeZoneDistroInstaller} and tzdatacheck.cpp.
+ */
+ private static final String SYSTEM_TZDATA_FILE_NAME = "tzdata";
+
+ /** A valid time zone rules version guaranteed to be older than {@link #RULES_VERSION_TWO} */
+ private static final String RULES_VERSION_ONE = "2016g";
+ /** A valid time zone rules version guaranteed to be newer than {@link #RULES_VERSION_ONE} */
+ private static final String RULES_VERSION_TWO = "2016h";
+ /**
+ * An arbitrary, valid time zone rules version used when it doesn't matter what the rules
+ * version is.
+ */
+ private static final String VALID_RULES_VERSION = RULES_VERSION_ONE;
+
+ /** An arbitrary valid revision number. */
+ private static final int VALID_REVISION = 1;
+
+ private String mDeviceAndroidRootDir;
+ private PathPair mTestRootDir;
+ private PathPair mSystemDir;
+ private PathPair mDataDir;
+
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // It's not clear how we would get this without invoking "/system/bin/sh", but we need the
+ // value first to do so. It has been hardcoded instead.
+ mDeviceAndroidRootDir = "/system";
+
+ // Create a test root directory on host and device.
+ Path hostTestRootDir = Files.createTempDirectory("tzdatacheck_test");
+ mTestRootDir = new PathPair(
+ hostTestRootDir,
+ "/data/local/tmp/tzdatacheck_test");
+ createDeviceDirectory(mTestRootDir);
+
+ // tzdatacheck requires two directories: a "system" path and a "data" path.
+ mSystemDir = mTestRootDir.createSubPath("system_dir");
+ mDataDir = mTestRootDir.createSubPath("data_dir");
+
+ // Create the host-side directory structure (for preparing files before pushing them to
+ // device and looking at files retrieved from device).
+ createHostDirectory(mSystemDir);
+ createHostDirectory(mDataDir);
+
+ // Create the equivalent device-side directory structure for receiving files.
+ createDeviceDirectory(mSystemDir);
+ createDeviceDirectory(mDataDir);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ // Remove the test root directories that have been created by this test.
+ deleteHostDirectory(mTestRootDir, true /* failOnError */);
+ deleteDeviceDirectory(mTestRootDir, true /* failOnError */);
+ super.tearDown();
+ }
+
+ public void testTooFewArgs() throws Exception {
+ // No need to set up or push files to the device for this test.
+ assertEquals(1, runTzDataCheckWithArgs(new String[0]));
+ assertEquals(1, runTzDataCheckWithArgs(new String[] { "oneArg" }));
+ }
+
+ // {dataDir}/staged exists but it is a file.
+ public void testStaging_stagingDirIsFile() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ // Create a file with the same name as the directory that tzdatacheck expects.
+ Files.write(dataStagedDir.hostPath, new byte[] { 'a' });
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code. Failures due to staging issues are
+ // generally ignored providing the device is left in a reasonable state.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the file was just ignored. This is a fairly arbitrary choice to leave it rather
+ // than delete.
+ assertDevicePathExists(dataStagedDir);
+ assertDevicePathIsFile(dataStagedDir);
+ }
+
+ // {dataDir}/staged exists but /current dir is a file.
+ public void testStaging_uninstall_currentDirIsFile() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+
+ // Create a staged uninstall.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ createStagedUninstallOnHost(dataStagedDir);
+
+ // Create a file with the same name as the directory that tzdatacheck expects.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ Files.write(dataCurrentDir.hostPath, new byte[] { 'a' });
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the device was left in a valid "uninstalled" state.
+ assertDevicePathDoesNotExist(dataStagedDir);
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/staged contains an uninstall, but there is nothing to uninstall.
+ public void testStaging_uninstall_noCurrent() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+
+ // Set up the /data directory structure on host.
+
+ // Create a staged uninstall.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ createStagedUninstallOnHost(dataStagedDir);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code. Failures due to staging issues are
+ // generally ignored providing the device is left in a reasonable state.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the device was left in a valid "uninstalled" state.
+ assertDevicePathDoesNotExist(dataStagedDir);
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/staged contains an uninstall, and there is something to uninstall.
+ public void testStaging_uninstall_withCurrent() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+
+ // Create a staged uninstall.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ createStagedUninstallOnHost(dataStagedDir);
+
+ // Create a current installed distro.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ TimeZoneDistro distro = createValidDistroBuilder().build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code. Failures due to staging issues are
+ // generally ignored providing the device is left in a reasonable state.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the device was left in a valid "uninstalled" state.
+ assertDevicePathDoesNotExist(dataStagedDir);
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/staged exists but /current dir is a file.
+ public void testStaging_install_currentDirIsFile() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+
+ // Create a staged install.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ TimeZoneDistro distro = createValidDistroBuilder().build();
+ unpackOnHost(dataStagedDir, distro);
+
+ // Create a file with the same name as the directory that tzdatacheck expects.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ Files.write(dataCurrentDir.hostPath, new byte[] { 'a' });
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code. Failures due to staging issues are
+ // generally ignored providing the device is left in a reasonable state.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the device was left in a valid "installed" state.
+ assertDevicePathDoesNotExist(dataStagedDir);
+ assertDeviceDirContainsDistro(dataCurrentDir, distro);
+ }
+
+ // {dataDir}/staged contains an install, but there is nothing to replace.
+ public void testStaging_install_noCurrent() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+
+ // Set up the /data directory structure on host.
+
+ // Create a staged install.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ TimeZoneDistro stagedDistro = createValidDistroBuilder().build();
+ unpackOnHost(dataStagedDir, stagedDistro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code. Failures due to staging issues are
+ // generally ignored providing the device is left in a reasonable state.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the device was left in a valid "installed" state.
+ assertDevicePathDoesNotExist(dataStagedDir);
+ assertDeviceDirContainsDistro(dataCurrentDir, stagedDistro);
+ }
+
+ // {dataDir}/staged contains an install, and there is something to replace.
+ public void testStaging_install_withCurrent() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ DistroVersion currentDistroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 1, VALID_RULES_VERSION, 1);
+ DistroVersion stagedDistroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 1, VALID_RULES_VERSION, 2);
+
+ // Set up the /data directory structure on host.
+
+ // Create a staged uninstall.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ TimeZoneDistro stagedDistro = createValidDistroBuilder()
+ .setDistroVersion(stagedDistroVersion)
+ .build();
+ unpackOnHost(dataStagedDir, stagedDistro);
+
+ // Create a current installed distro.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ TimeZoneDistro currentDistro = createValidDistroBuilder()
+ .setDistroVersion(currentDistroVersion)
+ .build();
+ unpackOnHost(dataCurrentDir, currentDistro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code. Failures due to staging issues are
+ // generally ignored providing the device is left in a reasonable state.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the device was left in a valid "installed" state.
+ // The stagedDistro should now be the one in the current dir.
+ assertDevicePathDoesNotExist(dataStagedDir);
+ assertDeviceDirContainsDistro(dataCurrentDir, stagedDistro);
+ }
+
+ // {dataDir}/staged contains an invalid install, and there is something to replace.
+ // Most of the invalid cases are tested without staging; this is just to prove that staging
+ // an invalid distro is handled the same.
+ public void testStaging_install_withCurrent_invalidStaged() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+
+ // Create a staged uninstall which contains invalid.
+ PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
+ TimeZoneDistro stagedDistro = createValidDistroBuilder()
+ .clearVersionForTests()
+ .buildUnvalidated();
+ unpackOnHost(dataStagedDir, stagedDistro);
+
+ // Create a current installed distro.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ TimeZoneDistro currentDistro = createValidDistroBuilder().build();
+ unpackOnHost(dataCurrentDir, currentDistro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code. The staged directory will have become the
+ // current one, but then it will be discovered to be invalid and will be removed.
+ assertEquals(3, runTzDataCheckOnDevice());
+
+ // Assert the device was left in a valid "uninstalled" state.
+ assertDevicePathDoesNotExist(dataStagedDir);
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // No {dataDir}/current exists.
+ public void testNoCurrentDataDir() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Deliberately not creating anything on host in the data dir here, leaving the empty
+ // structure.
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(0, runTzDataCheckOnDevice());
+ }
+
+ // {dataDir}/current exists but it is a file.
+ public void testCurrentDataDirIsFile() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ // Create a file with the same name as the directory that tzdatacheck expects.
+ Files.write(dataCurrentDir.hostPath, new byte[] { 'a' });
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(2, runTzDataCheckOnDevice());
+
+ // Assert the file was just ignored. This is a fairly arbitrary choice to leave it rather
+ // than delete.
+ assertDevicePathExists(dataCurrentDir);
+ assertDevicePathIsFile(dataCurrentDir);
+ }
+
+ // {dataDir}/current exists but is missing the distro version file.
+ public void testMissingDataDirDistroVersionFile() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ TimeZoneDistro distroWithoutAVersionFile = createValidDistroBuilder()
+ .clearVersionForTests()
+ .buildUnvalidated();
+ unpackOnHost(dataCurrentDir, distroWithoutAVersionFile);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(3, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was deleted.
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/current exists but the distro version file is short.
+ public void testShortDataDirDistroVersionFile() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ unpackOnHost(dataCurrentDir, createValidDistroBuilder().build());
+ // Replace the distro version file with a short file.
+ Path distroVersionFile =
+ dataCurrentDir.hostPath.resolve(TimeZoneDistro.DISTRO_VERSION_FILE_NAME);
+ assertHostFileExists(distroVersionFile);
+ Files.write(distroVersionFile, new byte[3]);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(3, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was deleted.
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/current exists and the distro version file is long enough, but contains junk.
+ public void testCorruptDistroVersionFile() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ unpackOnHost(dataCurrentDir, createValidDistroBuilder().build());
+
+ // Replace the distro version file with junk.
+ Path distroVersionFile =
+ dataCurrentDir.hostPath.resolve(TimeZoneDistro.DISTRO_VERSION_FILE_NAME);
+ assertHostFileExists(distroVersionFile);
+
+ int fileLength = (int) Files.size(distroVersionFile);
+ byte[] junkArray = new byte[fileLength]; // all zeros
+ Files.write(distroVersionFile, junkArray);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(4, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was deleted.
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/current exists but the distro version is incorrect.
+ public void testInvalidMajorDistroVersion_older() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ DistroVersion oldMajorDistroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION - 1, 1, VALID_RULES_VERSION, 1);
+ TimeZoneDistro distro = createValidDistroBuilder()
+ .setDistroVersion(oldMajorDistroVersion)
+ .build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(5, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was deleted.
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/current exists but the distro version is incorrect.
+ public void testInvalidMajorDistroVersion_newer() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ DistroVersion newMajorDistroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION + 1,
+ DistroVersion.CURRENT_FORMAT_MINOR_VERSION,
+ VALID_RULES_VERSION, VALID_REVISION);
+ TimeZoneDistro distro = createValidDistroBuilder()
+ .setDistroVersion(newMajorDistroVersion)
+ .build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(5, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was deleted.
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/current exists but the distro version is incorrect.
+ public void testInvalidMinorDistroVersion_older() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ DistroVersion oldMinorDistroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+ DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
+ VALID_RULES_VERSION, 1);
+ TimeZoneDistro distro = createValidDistroBuilder()
+ .setDistroVersion(oldMinorDistroVersion)
+ .build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(5, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was deleted.
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ // {dataDir}/current exists but the distro version is newer (which is accepted because it should
+ // be backwards compatible).
+ public void testValidMinorDistroVersion_newer() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ DistroVersion newMajorDistroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+ DistroVersion.CURRENT_FORMAT_MINOR_VERSION + 1,
+ VALID_RULES_VERSION, VALID_REVISION);
+ TimeZoneDistro distro = createValidDistroBuilder()
+ .setDistroVersion(newMajorDistroVersion)
+ .build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was not touched.
+ assertDeviceDirContainsDistro(dataCurrentDir, distro);
+ }
+
+ // {dataDir}/current is valid but the tzdata file in /system is missing.
+ public void testSystemTzDataFileMissing() throws Exception {
+ // Deliberately not writing anything in /system here.
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ TimeZoneDistro validDistro = createValidDistroBuilder().build();
+ unpackOnHost(dataCurrentDir, validDistro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(6, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was not touched.
+ assertDeviceDirContainsDistro(dataCurrentDir, validDistro);
+ }
+
+ // {dataDir}/current is valid but the tzdata file in /system has an invalid header.
+ public void testSystemTzDataFileCorrupt() throws Exception {
+ // Set up the /system directory structure on host.
+ byte[] invalidTzDataBytes = new byte[20];
+ Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZDATA_FILE_NAME), invalidTzDataBytes);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ TimeZoneDistro validDistro = createValidDistroBuilder().build();
+ unpackOnHost(dataCurrentDir, validDistro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(7, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was not touched.
+ assertDeviceDirContainsDistro(dataCurrentDir, validDistro);
+ }
+
+ // {dataDir}/current is valid and the tzdata file in /system is older.
+ public void testSystemTzRulesOlder() throws Exception {
+ // Set up the /system directory structure on host.
+ createSystemTzDataFileOnHost(RULES_VERSION_ONE);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ // Newer than RULES_VERSION_ONE in /system
+ final String distroRulesVersion = RULES_VERSION_TWO;
+ DistroVersion distroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+ DistroVersion.CURRENT_FORMAT_MINOR_VERSION, distroRulesVersion, VALID_REVISION);
+ TimeZoneDistro distro = createValidDistroBuilder()
+ .setDistroVersion(distroVersion)
+ .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
+ .build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was not touched.
+ assertDeviceDirContainsDistro(dataCurrentDir, distro);
+ }
+
+ // {dataDir}/current is valid and the tzdata file in /system is the same (and should be kept).
+ public void testSystemTzDataSame() throws Exception {
+ // Set up the /system directory structure on host.
+ final String systemRulesVersion = VALID_RULES_VERSION;
+ createSystemTzDataFileOnHost(systemRulesVersion);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ DistroVersion distroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+ DistroVersion.CURRENT_FORMAT_MINOR_VERSION, systemRulesVersion, VALID_REVISION);
+ TimeZoneDistro distro = createValidDistroBuilder()
+ .setDistroVersion(distroVersion)
+ .setTzDataFile(createValidTzDataBytes(systemRulesVersion))
+ .build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // Assert the current data directory was not touched.
+ assertDeviceDirContainsDistro(dataCurrentDir, distro);
+ }
+
+ // {dataDir}/current is valid and the tzdata file in /system is the newer.
+ public void testSystemTzDataNewer() throws Exception {
+ // Set up the /system directory structure on host.
+ String systemRulesVersion = RULES_VERSION_TWO;
+ createSystemTzDataFileOnHost(systemRulesVersion);
+
+ // Set up the /data directory structure on host.
+ PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
+ String distroRulesVersion = RULES_VERSION_ONE; // Older than the system version.
+ DistroVersion distroVersion = new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+ DistroVersion.CURRENT_FORMAT_MINOR_VERSION,
+ distroRulesVersion,
+ VALID_REVISION);
+ TimeZoneDistro distro = createValidDistroBuilder()
+ .setDistroVersion(distroVersion)
+ .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
+ .build();
+ unpackOnHost(dataCurrentDir, distro);
+
+ // Push the host test directory and contents to the device.
+ pushHostTestDirToDevice();
+
+ // Execute tzdatacheck and check the status code.
+ assertEquals(0, runTzDataCheckOnDevice());
+
+ // It is important the dataCurrentDir is deleted in this case - this test case is the main
+ // reason tzdatacheck exists.
+ assertDevicePathDoesNotExist(dataCurrentDir);
+ }
+
+ private void createSystemTzDataFileOnHost(String systemRulesVersion) throws IOException {
+ byte[] systemTzData = createValidTzDataBytes(systemRulesVersion);
+ Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZDATA_FILE_NAME), systemTzData);
+ }
+
+ private static void createStagedUninstallOnHost(PathPair stagedDir) throws Exception {
+ createHostDirectory(stagedDir);
+
+ PathPair uninstallTombstoneFile = stagedDir.createSubPath(UNINSTALL_TOMBSTONE_FILE_NAME);
+ // Create an empty file.
+ new FileOutputStream(uninstallTombstoneFile.hostFile()).close();
+ }
+
+ private static void unpackOnHost(PathPair path, TimeZoneDistro distro) throws Exception {
+ createHostDirectory(path);
+ distro.extractTo(path.hostFile());
+ }
+
+ private static TimeZoneDistroBuilder createValidDistroBuilder() throws Exception {
+ String distroRulesVersion = VALID_RULES_VERSION;
+ DistroVersion validDistroVersion =
+ new DistroVersion(
+ DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+ DistroVersion.CURRENT_FORMAT_MINOR_VERSION,
+ distroRulesVersion, VALID_REVISION);
+ return new TimeZoneDistroBuilder()
+ .setDistroVersion(validDistroVersion)
+ .setTzDataFile(createValidTzDataBytes(distroRulesVersion))
+ .setIcuDataFile(new byte[10]);
+ }
+
+ private static byte[] createValidTzDataBytes(String rulesVersion) {
+ return new ZoneInfoTestHelper.TzDataBuilder()
+ .initializeToValid()
+ .setHeaderMagic("tzdata" + rulesVersion)
+ .build();
+ }
+
+ private int runTzDataCheckOnDevice() throws Exception {
+ return runTzDataCheckWithArgs(new String[] { mSystemDir.devicePath, mDataDir.devicePath });
+ }
+
+ private int runTzDataCheckWithArgs(String[] args) throws Exception {
+ String command = createTzDataCheckCommand(mDeviceAndroidRootDir, args);
+ return executeCommandOnDeviceWithResultCode(command).statusCode;
+ }
+
+ private static String createTzDataCheckCommand(String rootDir, String[] args) {
+ StringJoiner joiner = new StringJoiner(" ");
+ String tzDataCheckCommand = rootDir + "/bin/tzdatacheck";
+ joiner.add(tzDataCheckCommand);
+ for (String arg : args) {
+ joiner.add(arg);
+ }
+ return joiner.toString();
+ }
+
+ private static void assertHostFileExists(Path path) {
+ assertTrue(Files.exists(path));
+ }
+
+ private String executeCommandOnDeviceRaw(String command) throws DeviceNotAvailableException {
+ return getDevice().executeShellCommand(command);
+ }
+
+ private void createDeviceDirectory(PathPair dir) throws DeviceNotAvailableException {
+ executeCommandOnDeviceRaw("mkdir -p " + dir.devicePath);
+ }
+
+ private static void createHostDirectory(PathPair dir) throws Exception {
+ Files.createDirectory(dir.hostPath);
+ }
+
+ private static class ShellResult {
+ final String output;
+ final int statusCode;
+
+ private ShellResult(String output, int statusCode) {
+ this.output = output;
+ this.statusCode = statusCode;
+ }
+ }
+
+ private ShellResult executeCommandOnDeviceWithResultCode(String command) throws Exception {
+ // A file to hold the script we're going to create.
+ PathPair scriptFile = mTestRootDir.createSubPath("script.sh");
+ // A file to hold the output of the script.
+ PathPair scriptOut = mTestRootDir.createSubPath("script.out");
+
+ // The content of the script. Runs the command, capturing stdout and stderr to scriptOut
+ // and printing the result code.
+ String hostScriptContent = command + " > " + scriptOut.devicePath + " 2>&1 ; echo -n $?";
+
+ // Parse and return the result.
+ try {
+ Files.write(scriptFile.hostPath, hostScriptContent.getBytes(StandardCharsets.US_ASCII));
+
+ // Push the script to the device.
+ pushFile(scriptFile);
+
+ // Execute the script using "sh".
+ String execCommandUnderShell =
+ mDeviceAndroidRootDir + "/bin/sh " + scriptFile.devicePath;
+ String resultCodeString = executeCommandOnDeviceRaw(execCommandUnderShell);
+
+ // Pull back scriptOut to the host and read the content.
+ pullFile(scriptOut);
+ byte[] outputBytes = Files.readAllBytes(scriptOut.hostPath);
+ String output = new String(outputBytes, StandardCharsets.US_ASCII);
+
+ int resultCode;
+ try {
+ resultCode = Integer.parseInt(resultCodeString);
+ } catch (NumberFormatException e) {
+ fail("Command: " + command
+ + " returned a non-integer: \"" + resultCodeString + "\""
+ + ", output=\"" + output + "\"");
+ return null;
+ }
+ return new ShellResult(output, resultCode);
+ } finally {
+ deleteDeviceFile(scriptFile, false /* failOnError */);
+ deleteDeviceFile(scriptOut, false /* failOnError */);
+ deleteHostFile(scriptFile, false /* failOnError */);
+ deleteHostFile(scriptOut, false /* failOnError */);
+ }
+ }
+
+ private void pushHostTestDirToDevice() throws Exception {
+ assertTrue(getDevice().pushDir(mTestRootDir.hostFile(), mTestRootDir.devicePath));
+ }
+
+ private void pullFile(PathPair file) throws DeviceNotAvailableException {
+ assertTrue("Could not pull file " + file.devicePath + " to " + file.hostFile(),
+ getDevice().pullFile(file.devicePath, file.hostFile()));
+ }
+
+ private void pushFile(PathPair file) throws DeviceNotAvailableException {
+ assertTrue("Could not push file " + file.hostFile() + " to " + file.devicePath,
+ getDevice().pushFile(file.hostFile(), file.devicePath));
+ }
+
+ private void deleteHostFile(PathPair file, boolean failOnError) {
+ try {
+ Files.deleteIfExists(file.hostPath);
+ } catch (IOException e) {
+ if (failOnError) {
+ fail(e);
+ }
+ }
+ }
+
+ private void deleteDeviceDirectory(PathPair dir, boolean failOnError)
+ throws DeviceNotAvailableException {
+ String deviceDir = dir.devicePath;
+ try {
+ executeCommandOnDeviceRaw("rm -r " + deviceDir);
+ } catch (Exception e) {
+ if (failOnError) {
+ throw deviceFail(e);
+ }
+ }
+ }
+
+ private void deleteDeviceFile(PathPair file, boolean failOnError)
+ throws DeviceNotAvailableException {
+ try {
+ assertDevicePathIsFile(file);
+ executeCommandOnDeviceRaw("rm " + file.devicePath);
+ } catch (Exception e) {
+ if (failOnError) {
+ throw deviceFail(e);
+ }
+ }
+ }
+
+ private static void deleteHostDirectory(PathPair dir, final boolean failOnError) {
+ Path hostPath = dir.hostPath;
+ if (Files.exists(hostPath)) {
+ Consumer<Path> pathConsumer = file -> {
+ try {
+ Files.delete(file);
+ } catch (Exception e) {
+ if (failOnError) {
+ fail(e);
+ }
+ }
+ };
+
+ try {
+ Files.walk(hostPath).sorted(Comparator.reverseOrder()).forEach(pathConsumer);
+ } catch (IOException e) {
+ fail(e);
+ }
+ }
+ }
+
+ private void assertDevicePathExists(PathPair path) throws DeviceNotAvailableException {
+ assertTrue(getDevice().doesFileExist(path.devicePath));
+ }
+
+ private void assertDeviceDirContainsDistro(PathPair distroPath, TimeZoneDistro expectedDistro)
+ throws Exception {
+ // Pull back just the version file and compare it.
+ File localFile = mTestRootDir.createSubPath("temp.file").hostFile();
+ try {
+ String remoteVersionFile = distroPath.devicePath + "/"
+ + TimeZoneDistro.DISTRO_VERSION_FILE_NAME;
+ assertTrue("Could not pull file " + remoteVersionFile + " to " + localFile,
+ getDevice().pullFile(remoteVersionFile, localFile));
+
+ byte[] bytes = Files.readAllBytes(localFile.toPath());
+ assertArrayEquals(bytes, expectedDistro.getDistroVersion().toBytes());
+ } finally {
+ localFile.delete();
+ }
+ }
+
+ private void assertDevicePathDoesNotExist(PathPair path) throws DeviceNotAvailableException {
+ assertFalse(getDevice().doesFileExist(path.devicePath));
+ }
+
+ private void assertDevicePathIsFile(PathPair path) throws DeviceNotAvailableException {
+ // This check cannot rely on getDevice().getFile(devicePath).isDirectory() here because that
+ // requires that the user has rights to list all files beneath each and every directory in
+ // the path. That is not the case for the shell user and the /data and /data/local
+ // directories. http://b/35753041.
+ String output = executeCommandOnDeviceRaw("stat -c %F " + path.devicePath);
+ assertTrue(path.devicePath + " not a file. Received: " + output,
+ output.startsWith("regular") && output.endsWith("file\n"));
+ }
+
+ private static DeviceNotAvailableException deviceFail(Exception e)
+ throws DeviceNotAvailableException {
+ if (e instanceof DeviceNotAvailableException) {
+ throw (DeviceNotAvailableException) e;
+ }
+ fail(e);
+ return null;
+ }
+
+ private static void fail(Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ /** A path that has equivalents on both host and device. */
+ private static class PathPair {
+ private final Path hostPath;
+ private final String devicePath;
+
+ PathPair(Path hostPath, String devicePath) {
+ this.hostPath = hostPath;
+ this.devicePath = devicePath;
+ }
+
+ File hostFile() {
+ return hostPath.toFile();
+ }
+
+ PathPair createSubPath(String s) {
+ return new PathPair(hostPath.resolve(s), devicePath + "/" + s);
+ }
+ }
+}
diff --git a/tests/libcore/wycheproof/Android.mk b/tests/libcore/wycheproof/Android.mk
new file mode 100644
index 0000000..d568e6a
--- /dev/null
+++ b/tests/libcore/wycheproof/Android.mk
@@ -0,0 +1,55 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofTestCases
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ cts-core-test-runner \
+ wycheproof
+
+LOCAL_JAVA_LIBRARIES := \
+ bouncycastle \
+ conscrypt
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+LOCAL_DEX_PREOPT := false
+LOCAL_JACK_FLAGS := --multi-dex native
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+# Include both the 32 and 64 bit versions of libjavacoretests,
+# where applicable.
+LOCAL_MULTILIB := both
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_JAVA_RESOURCE_FILES := \
+ libcore/expectations/brokentests.txt \
+ libcore/expectations/icebox.txt \
+ libcore/expectations/knownfailures.txt \
+ libcore/expectations/taggedtests.txt
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/libcore/wycheproof/AndroidManifest.xml b/tests/libcore/wycheproof/AndroidManifest.xml
new file mode 100644
index 0000000..09b9da1
--- /dev/null
+++ b/tests/libcore/wycheproof/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.libcore.cts.wycheproof">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.libcore.cts.wycheproof"
+ android:label="CTS Libcore Wycheproof test cases" />
+
+</manifest>
diff --git a/tests/libcore/wycheproof/AndroidTest.xml b/tests/libcore/wycheproof/AndroidTest.xml
new file mode 100644
index 0000000..f933565
--- /dev/null
+++ b/tests/libcore/wycheproof/AndroidTest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for CTS Libcore Wycheproof test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <!-- this has just the instrumentation which acts as the tests we want to run -->
+ <option name="test-file-name" value="CtsLibcoreWycheproofTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.compatibility.testtype.LibcoreTest" >
+ <option name="package" value="android.libcore.cts.wycheproof" />
+ <!-- The individual test cases don't work unless they're run in the
+ context of one of the suites, so we have to limit the test
+ infrastructure to only running the test suites. -->
+ <option name="test-package" value="android.libcore.cts.wycheproof" />
+ <option name="instrumentation-arg" key="listener"
+ value="com.android.cts.runner.CtsTestRunListener" />
+ <option name="instrumentation-arg" key="filter"
+ value="com.android.cts.core.runner.ExpectationBasedFilter" />
+ <option name="core-expectation" value="/knownfailures.txt" />
+ <option name="core-expectation" value="/brokentests.txt" />
+ <option name="core-expectation" value="/icebox.txt" />
+ <option name="core-expectation" value="/taggedtests.txt" />
+ <option name="runtime-hint" value="10m"/>
+ </test>
+</configuration>
diff --git a/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleSupportProvider.java b/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleSupportProvider.java
new file mode 100644
index 0000000..d6ab5c1
--- /dev/null
+++ b/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleSupportProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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.libcore.cts.wycheproof;
+
+import java.security.Provider;
+
+/**
+ * Provides a small number of exports to allow Bouncy Castle tests to function properly.
+ * Our modified version of Bouncy Castle depends on Conscrypt for a few pieces of
+ * functionality, but in tests we don't want to have Conscrypt installed so that we can test
+ * Bouncy Castle properly. We install this provider instead.
+ */
+public class BouncyCastleSupportProvider extends Provider {
+
+ // The classes are jarjared, so this is the prefix in practice.
+ private static final String PREFIX = "com.android.org.conscrypt.";
+
+ public BouncyCastleSupportProvider() {
+ // Our modified version of Bouncy Castle specifically expects certain algorithms
+ // to be provided by a provider named "AndroidOpenSSL", so we use that name
+ super("AndroidOpenSSL", 0.0,
+ "Provides algorithms that Bouncy Castle needs to work in tests");
+
+ // Conscrypt is the only SecureRandom implementation
+ put("SecureRandom.SHA1PRNG", PREFIX + "OpenSSLRandom");
+
+ // Bouncy Castle's MACs are backed by Conscrypt's MessageDigests
+ put("MessageDigest.SHA-1", PREFIX + "OpenSSLMessageDigestJDK$SHA1");
+ put("MessageDigest.SHA-224", PREFIX + "OpenSSLMessageDigestJDK$SHA224");
+ put("MessageDigest.SHA-256", PREFIX + "OpenSSLMessageDigestJDK$SHA256");
+ put("MessageDigest.SHA-384", PREFIX + "OpenSSLMessageDigestJDK$SHA384");
+ put("MessageDigest.SHA-512", PREFIX + "OpenSSLMessageDigestJDK$SHA512");
+ }
+}
diff --git a/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleTest.java b/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleTest.java
new file mode 100644
index 0000000..dfb71e8
--- /dev/null
+++ b/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/BouncyCastleTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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.libcore.cts.wycheproof;
+
+import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.google.security.wycheproof.AesGcmTest;
+import com.google.security.wycheproof.BasicTest;
+import com.google.security.wycheproof.CipherInputStreamTest;
+import com.google.security.wycheproof.CipherOutputStreamTest;
+import com.google.security.wycheproof.DhTest;
+import com.google.security.wycheproof.DhiesTest;
+import com.google.security.wycheproof.DsaTest;
+import com.google.security.wycheproof.EcKeyTest;
+import com.google.security.wycheproof.EcdhTest;
+import com.google.security.wycheproof.EcdsaTest;
+import com.google.security.wycheproof.RsaEncryptionTest;
+import com.google.security.wycheproof.RsaKeyTest;
+import com.google.security.wycheproof.RsaSignatureTest;
+import com.google.security.wycheproof.TestUtil;
+import com.google.security.wycheproof.WycheproofRunner;
+import com.google.security.wycheproof.WycheproofRunner.Fast;
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Checks that our Bouncy Castle provider properly implements all its functionality.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ DhTest.class,
+ DhiesTest.class,
+ DsaTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class,
+})
+@Provider(ProviderType.BOUNCY_CASTLE)
+@Fast
+public final class BouncyCastleTest {
+
+ private static final List<java.security.Provider> previousProviders = new ArrayList<>();
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ previousProviders.clear();
+ previousProviders.addAll(Arrays.asList(Security.getProviders()));
+ TestUtil.installOnlyThisProvider(new BouncyCastleProvider());
+ Security.addProvider(new BouncyCastleSupportProvider());
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ for (java.security.Provider p : Security.getProviders()) {
+ Security.removeProvider(p.getName());
+ }
+ for (java.security.Provider p : previousProviders) {
+ Security.addProvider(p);
+ }
+ }
+}
diff --git a/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/ConscryptTest.java b/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/ConscryptTest.java
new file mode 100644
index 0000000..bee62fa
--- /dev/null
+++ b/tests/libcore/wycheproof/src/android/libcore/cts/wycheproof/ConscryptTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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.libcore.cts.wycheproof;
+
+import com.android.org.conscrypt.OpenSSLProvider;
+import com.google.security.wycheproof.AesGcmTest;
+import com.google.security.wycheproof.BasicTest;
+import com.google.security.wycheproof.CipherInputStreamTest;
+import com.google.security.wycheproof.CipherOutputStreamTest;
+import com.google.security.wycheproof.EcKeyTest;
+import com.google.security.wycheproof.EcdhTest;
+import com.google.security.wycheproof.EcdsaTest;
+import com.google.security.wycheproof.RsaEncryptionTest;
+import com.google.security.wycheproof.RsaKeyTest;
+import com.google.security.wycheproof.RsaSignatureTest;
+import com.google.security.wycheproof.TestUtil;
+import com.google.security.wycheproof.WycheproofRunner;
+import com.google.security.wycheproof.WycheproofRunner.Fast;
+import com.google.security.wycheproof.WycheproofRunner.Provider;
+import com.google.security.wycheproof.WycheproofRunner.ProviderType;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Checks that our Conscrypt provider properly implements all its functionality.
+ */
+@RunWith(WycheproofRunner.class)
+@SuiteClasses({
+ AesGcmTest.class,
+ BasicTest.class,
+ CipherInputStreamTest.class,
+ CipherOutputStreamTest.class,
+ EcKeyTest.class,
+ EcdhTest.class,
+ EcdsaTest.class,
+ RsaEncryptionTest.class,
+ RsaKeyTest.class,
+ RsaSignatureTest.class
+})
+@Provider(ProviderType.CONSCRYPT)
+@Fast
+public final class ConscryptTest {
+
+ private static final List<java.security.Provider> previousProviders = new ArrayList<>();
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ previousProviders.clear();
+ previousProviders.addAll(Arrays.asList(Security.getProviders()));
+ TestUtil.installOnlyThisProvider(new OpenSSLProvider());
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ for (java.security.Provider p : Security.getProviders()) {
+ Security.removeProvider(p.getName());
+ }
+ for (java.security.Provider p : previousProviders) {
+ Security.addProvider(p);
+ }
+ }
+}
diff --git a/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt b/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
index ebcbd78..a2e6dc4 100644
--- a/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
+++ b/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
@@ -11,45 +11,16 @@
},
*/
{
- description: "Class cannot be instantiated, cannot find resources android/icu/dev/test/serializable/data",
- name: "android.icu.dev.test.serializable.CompatibilityTest",
- bug: "27310873"
-},
-{
- description: "Cannot find any classes to test because .class files are not treated as resources in APK",
- name: "android.icu.dev.test.serializable.CoverageTest",
- bug: "27666677"
-},
-{
description: "Serialized forms have not been converted to use repackaged classes",
name: "android.icu.dev.test.format.NumberFormatRegressionTest#TestSerialization",
bug: "27374606"
},
{
- description: "android.icu.charset package not available in repackaged Android library",
- names: [
- "android.icu.dev.test.charset.TestCharset",
- "android.icu.dev.test.charset.TestConversion",
- "android.icu.dev.test.charset.TestSelection"
- ],
- bug: "27373370"
-},
-{
description: "Fails on host and on device in same way before and after packaging",
name: "android.icu.dev.test.bidi.TestCompatibility#testCompatibility",
bug: "23995372"
},
{
- description: "Problem with negative multiplier, not a regression",
- name: "android.icu.dev.test.format.NumberFormatTest#TestNonpositiveMultiplier",
- bug: "19185440"
-},
-{
- description: "Wrong case for exponent separator",
- name: "android.icu.dev.test.format.PluralRulesTest#testOverUnderflow",
- bug: "27566754"
-},
-{
description: "Checks differences in DecimalFormat classes from ICU4J and JDK but on Android java.text.DecimalFormat is implemented in terms of ICU4J",
name: "android.icu.dev.test.format.NumberFormatTest#TestDataDrivenJDK",
bug: "27711713"
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index d3c392c..1953834 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -504,12 +504,16 @@
if (!hasCamera()) {
return;
}
+ mCamera = Camera.open(0);
+ setSupportedResolution(mCamera);
+ mCamera.unlock();
+
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mMediaRecorder.setOutputFile(OUTPUT_PATH2);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
- mMediaRecorder.setVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT);
+ mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
FileOutputStream fos = new FileOutputStream(OUTPUT_PATH2);
FileDescriptor fd = fos.getFD();
@@ -675,12 +679,16 @@
MediaUtils.skipTest("no microphone, camera, or codecs");
return;
}
+ mCamera = Camera.open(0);
+ setSupportedResolution(mCamera);
+ mCamera.unlock();
+
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
- mMediaRecorder.setVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT);
+ mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
mMediaRecorder.setVideoEncodingBitRate(256000);
mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
mMediaRecorder.setMaxFileSize(fileSize);
@@ -873,6 +881,7 @@
mCamera = Camera.open(0);
Camera.Parameters params = mCamera.getParameters();
frameRate = params.getPreviewFrameRate();
+ setSupportedResolution(mCamera);
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
@@ -890,7 +899,7 @@
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoFrameRate(frameRate);
- mMediaRecorder.setVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT);
+ mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
if (hasAudio) {
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/SingleSourceForEachTest.java b/tests/tests/renderscript/src/android/renderscript/cts/SingleSourceForEachTest.java
index 06eb606..5f17655 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/SingleSourceForEachTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/SingleSourceForEachTest.java
@@ -125,4 +125,11 @@
baselineOutputAlloc.copyTo(baselineOutputArray);
checkArray(baselineOutputArray, testOutputArray, Y, X, X);
}
+
+ public void testConsistency() {
+ s.invoke_testConsistency(testInputAlloc, testOutputAlloc);
+ mRS.finish();
+ waitForMessage();
+ checkForErrors();
+ }
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/single_source_script.rs b/tests/tests/renderscript/src/android/renderscript/cts/single_source_script.rs
index 5e35aa3..c3e322b 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/single_source_script.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/single_source_script.rs
@@ -27,9 +27,9 @@
}
void RS_KERNEL bar(int x, int y) {
- int a = rsGetElementAt_int(gAllocOut, x, y);
- a++;
- rsSetElementAt_int(gAllocOut, a, x, y);
+ int a = rsGetElementAt_int(gAllocOut, x, y);
+ a++;
+ rsSetElementAt_int(gAllocOut, a, x, y);
}
void testSingleInput(rs_allocation in, rs_allocation out) {
@@ -58,3 +58,19 @@
opts.yEnd = dimY;
rsForEachWithOptions(bar, &opts);
}
+
+void testConsistency(rs_allocation in, rs_allocation out) {
+ rsForEach(foo, in, out);
+ const uint32_t dimX = rsAllocationGetDimX(in);
+ const uint32_t dimY = rsAllocationGetDimY(in);
+ for (int i = 0; i < dimX; i++) {
+ for (int j = 0; j < dimY; j++) {
+ if (rsGetElementAt_int(out, i, j) != 2 * rsGetElementAt_int(in, i, j)) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ return;
+ }
+ }
+ }
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+}
+
diff --git a/tests/tests/telecom/Android.mk b/tests/tests/telecom/Android.mk
index 6b12ce8..c81a811 100644
--- a/tests/tests/telecom/Android.mk
+++ b/tests/tests/telecom/Android.mk
@@ -28,7 +28,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 6dcd6ca..f0cad67 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -74,6 +74,13 @@
</intent-filter>
</receiver>
+ <receiver android:name="android.telecom.cts.MockPhoneAccountChangedReceiver">
+ <intent-filter>
+ <action android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED"/>
+ <action android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED"/>
+ </intent-filter>
+ </receiver>
+
<activity android:name="android.telecom.cts.MockDialerActivity">
<intent-filter>
<action android:name="android.intent.action.DIAL" />
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 3a70102..93e4c65 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -68,6 +68,10 @@
TestUtils.InvokeCounter mOnConnectionEventCounter;
TestUtils.InvokeCounter mOnExtrasChangedCounter;
TestUtils.InvokeCounter mOnPropertiesChangedCounter;
+ TestUtils.InvokeCounter mOnRttModeChangedCounter;
+ TestUtils.InvokeCounter mOnRttStatusChangedCounter;
+ TestUtils.InvokeCounter mOnRttInitiationFailedCounter;
+ TestUtils.InvokeCounter mOnRttRequestCounter;
Bundle mPreviousExtras;
int mPreviousProperties = -1;
@@ -228,6 +232,27 @@
Log.i(TAG, "onSilenceRinger");
mOnSilenceRingerCounter.invoke();
}
+
+ @Override
+ public void onRttModeChanged(Call call, int mode) {
+ mOnRttModeChangedCounter.invoke(call, mode);
+ }
+
+ @Override
+ public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) {
+ mOnRttStatusChangedCounter.invoke(call, enabled, rttCall);
+ }
+
+ @Override
+ public void onRttRequest(Call call, int id) {
+ mOnRttRequestCounter.invoke(call, id);
+ }
+
+ @Override
+ public void onRttInitiationFailure(Call call, int reason) {
+ mOnRttInitiationFailedCounter.invoke(call, reason);
+ }
+
};
MockInCallService.setCallbacks(mInCallCallbacks);
@@ -242,6 +267,11 @@
mOnConnectionEventCounter = new TestUtils.InvokeCounter("OnConnectionEvent");
mOnExtrasChangedCounter = new TestUtils.InvokeCounter("OnDetailsChangedCounter");
mOnPropertiesChangedCounter = new TestUtils.InvokeCounter("OnPropertiesChangedCounter");
+ mOnRttModeChangedCounter = new TestUtils.InvokeCounter("mOnRttModeChangedCounter");
+ mOnRttStatusChangedCounter = new TestUtils.InvokeCounter("mOnRttStatusChangedCounter");
+ mOnRttInitiationFailedCounter =
+ new TestUtils.InvokeCounter("mOnRttInitiationFailedCounter");
+ mOnRttRequestCounter = new TestUtils.InvokeCounter("mOnRttRequestCounter");
}
/**
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index 1895b0f..0b70f1b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -19,6 +19,8 @@
import static android.telecom.cts.TestUtils.*;
import android.content.ComponentName;
+import android.content.Context;
+import android.media.AudioManager;
import android.telecom.Call;
import android.telecom.Connection;
import android.telecom.ConnectionService;
@@ -27,7 +29,8 @@
import java.util.Collection;
/**
- * Test some additional {@link ConnectionService} APIs not already covered by other tests.
+ * Test some additional {@link ConnectionService} and {@link Connection} APIs not already covered
+ * by other tests.
*/
public class ConnectionServiceTest extends BaseTelecomTestWithMockServices {
@@ -104,6 +107,23 @@
assertCallState(call, Call.STATE_DIALING);
}
+ public void testVoipAudioModePropagation() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ placeAndVerifyCall();
+ MockConnection connection = verifyConnectionForOutgoingCall();
+ connection.setAudioModeIsVoip(true);
+ waitOnAllHandlers(getInstrumentation());
+
+ AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ assertEquals(AudioManager.MODE_IN_COMMUNICATION, audioManager.getMode());
+ connection.setAudioModeIsVoip(false);
+ waitOnAllHandlers(getInstrumentation());
+ assertEquals(AudioManager.MODE_IN_CALL, audioManager.getMode());
+ }
+
public void testGetAllConnections() {
if (!mShouldTestTelecom) {
return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index 5183bd4..da4fcf5 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -37,6 +37,9 @@
public static final int ON_CALL_EVENT = 2;
public static final int ON_PULL_EXTERNAL_CALL = 3;
public static final int ON_EXTRAS_CHANGED = 4;
+ public static final int ON_START_RTT = 5;
+ public static final int ON_RTT_REQUEST_RESPONSE = 6;
+ public static final int ON_STOP_RTT = 7;
private CallAudioState mCallAudioState =
new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, ROUTE_EARPIECE | ROUTE_SPEAKER);
@@ -46,6 +49,7 @@
private MockVideoProvider mMockVideoProvider;
private PhoneAccountHandle mPhoneAccountHandle;
private RemoteConnection mRemoteConnection = null;
+ private RttTextStream mRttTextStream;
private SparseArray<InvokeCounter> mInvokeCounterMap = new SparseArray<>(10);
@@ -187,6 +191,36 @@
}
}
+ @Override
+ public void onStartRtt(RttTextStream rttTextStream) {
+ super.onStartRtt(rttTextStream);
+ if (mInvokeCounterMap.get(ON_START_RTT) != null) {
+ mInvokeCounterMap.get(ON_START_RTT).invoke(rttTextStream);
+ }
+ }
+
+ @Override
+ public void handleRttUpgradeResponse(RttTextStream rttTextStream) {
+ super.handleRttUpgradeResponse(rttTextStream);
+ if (rttTextStream != null) {
+ setRttTextStream(rttTextStream);
+ setConnectionProperties(getConnectionProperties() | PROPERTY_IS_RTT);
+ }
+
+ if (mInvokeCounterMap.get(ON_RTT_REQUEST_RESPONSE) != null) {
+ mInvokeCounterMap.get(ON_RTT_REQUEST_RESPONSE).invoke(rttTextStream);
+ }
+ }
+
+ @Override
+ public void onStopRtt() {
+ super.onStopRtt();
+
+ if (mInvokeCounterMap.get(ON_STOP_RTT) != null) {
+ mInvokeCounterMap.get(ON_STOP_RTT).invoke();
+ }
+ }
+
public int getCurrentState() {
return mState;
}
@@ -264,6 +298,14 @@
return mRemoteConnection;
}
+ public void setRttTextStream(RttTextStream rttTextStream) {
+ mRttTextStream = rttTextStream;
+ }
+
+ public RttTextStream getRttTextStream() {
+ return mRttTextStream;
+ }
+
private static String getCounterLabel(int counterIndex) {
switch (counterIndex) {
case ON_POST_DIAL_WAIT:
@@ -274,6 +316,12 @@
return "onPullExternalCall";
case ON_EXTRAS_CHANGED:
return "onExtrasChanged";
+ case ON_START_RTT:
+ return "onStartRtt";
+ case ON_RTT_REQUEST_RESPONSE:
+ return "onRttRequestResponse";
+ case ON_STOP_RTT:
+ return "onStopRtt";
default:
return "Callback";
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
index 4b9063d..6e022e6 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
@@ -65,6 +65,11 @@
}
connection.setVideoState(request.getVideoState());
connection.setInitializing();
+ if (request.isRequestingRtt()) {
+ connection.setRttTextStream(request.getRttTextStream());
+ connection.setConnectionProperties(connection.getConnectionProperties() |
+ Connection.PROPERTY_IS_RTT);
+ }
outgoingConnections.add(connection);
lock.release();
@@ -82,6 +87,11 @@
| Connection.CAPABILITY_HOLD);
connection.createMockVideoProvider();
((Connection) connection).setVideoState(request.getVideoState());
+ if (request.isRequestingRtt()) {
+ connection.setRttTextStream(request.getRttTextStream());
+ connection.setConnectionProperties(connection.getConnectionProperties() |
+ Connection.PROPERTY_IS_RTT);
+ }
connection.setRinging();
incomingConnections.add(connection);
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
index 4ff3cb6..e13335e 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
@@ -61,6 +61,10 @@
public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
public void onSilenceRinger() {}
public void onConnectionEvent(Call call, String event, Bundle extras) {}
+ public void onRttModeChanged(Call call, int mode) {}
+ public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) {}
+ public void onRttRequest(Call call, int id) {}
+ public void onRttInitiationFailure(Call call, int reason) {}
final public MockInCallService getService() {
return mService;
@@ -153,6 +157,38 @@
getCallbacks().onConnectionEvent(call, event, extras);
}
}
+
+ @Override
+ public void onRttModeChanged(Call call, int mode) {
+ super.onRttModeChanged(call, mode);
+ if (getCallbacks() != null) {
+ getCallbacks().onRttModeChanged(call, mode);
+ }
+ }
+
+ @Override
+ public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) {
+ super.onRttStatusChanged(call, enabled, rttCall);
+ if (getCallbacks() != null) {
+ getCallbacks().onRttStatusChanged(call, enabled, rttCall);
+ }
+ }
+
+ @Override
+ public void onRttRequest(Call call, int id) {
+ super.onRttRequest(call, id);
+ if (getCallbacks() != null) {
+ getCallbacks().onRttRequest(call, id);
+ }
+ }
+
+ @Override
+ public void onRttInitiationFailure(Call call, int reason) {
+ super.onRttInitiationFailure(call, reason);
+ if (getCallbacks() != null) {
+ getCallbacks().onRttInitiationFailure(call, reason);
+ }
+ }
};
private void saveVideoCall(Call call, VideoCall videoCall) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockPhoneAccountChangedReceiver.java b/tests/tests/telecom/src/android/telecom/cts/MockPhoneAccountChangedReceiver.java
new file mode 100644
index 0000000..0601d75
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/MockPhoneAccountChangedReceiver.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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.telecom.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+
+/**
+ * Receives {@link android.telecom.TelecomManager#ACTION_PHONE_ACCOUNT_REGISTERED} and
+ * {@link android.telecom.TelecomManager#ACTION_PHONE_ACCOUNT_UNREGISTERED} intents.
+ */
+public class MockPhoneAccountChangedReceiver extends BroadcastReceiver {
+ public interface IntentListener {
+ void onPhoneAccountRegistered(PhoneAccountHandle handle);
+ void onPhoneAccountUnregistered(PhoneAccountHandle handle);
+ }
+
+ private static IntentListener sIntentListener = null;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (sIntentListener != null) {
+ if (TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED.equals(intent.getAction())) {
+ sIntentListener.onPhoneAccountRegistered(intent.getParcelableExtra(
+ TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE));
+ } else if (TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED.equals(
+ intent.getAction())) {
+ sIntentListener.onPhoneAccountUnregistered(intent.getParcelableExtra(
+ TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE));
+ }
+ }
+ }
+
+ public static void setIntentListener(IntentListener listener) {
+ sIntentListener = listener;
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index 4374516..c9b5000 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -43,6 +43,22 @@
public static final int TEST_LENGTH = 10;
public static final String TEST_ENCODING = "enUS";
+ private TestUtils.InvokeCounter mPhoneAccountRegisteredLatch;
+ private TestUtils.InvokeCounter mPhoneAccountUnRegisteredLatch;
+
+ MockPhoneAccountChangedReceiver.IntentListener mPhoneAccountIntentListener =
+ new MockPhoneAccountChangedReceiver.IntentListener() {
+ @Override
+ public void onPhoneAccountRegistered(PhoneAccountHandle handle) {
+ mPhoneAccountRegisteredLatch.invoke(handle);
+ }
+
+ @Override
+ public void onPhoneAccountUnregistered(PhoneAccountHandle handle) {
+ mPhoneAccountUnRegisteredLatch.invoke(handle);
+ }
+ };
+
private static Bundle createTestBundle() {
Bundle testBundle = new Bundle();
testBundle.putInt(PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH, TEST_LENGTH);
@@ -96,6 +112,8 @@
return;
}
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+ mPhoneAccountRegisteredLatch = new TestUtils.InvokeCounter("registerPhoneAcct");
+ mPhoneAccountUnRegisteredLatch = new TestUtils.InvokeCounter("unRegisterPhoneAcct");
}
@Override
@@ -225,4 +243,38 @@
assertTrue("Phone account should support voicemail URI scheme.",
retrievedPhoneAccount.supportsUriScheme(PhoneAccount.SCHEME_VOICEMAIL));
}
+
+ /**
+ * Verifies that the {@link TelecomManager#ACTION_PHONE_ACCOUNT_REGISTERED} intent is sent to
+ * the default dialer when a phone account is registered and,
+ * {@link TelecomManager#ACTION_PHONE_ACCOUNT_UNREGISTERED} is sent when a phone account is
+ * unregistered.
+ * @throws Exception
+ */
+ public void testRegisterUnregisterPhoneAccountIntent() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ MockPhoneAccountChangedReceiver.setIntentListener(mPhoneAccountIntentListener);
+ String previousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation());
+ try {
+ TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
+
+ mTelecomManager.registerPhoneAccount(TEST_NO_SIM_PHONE_ACCOUNT);
+
+ mPhoneAccountRegisteredLatch.waitForCount(1);
+ PhoneAccountHandle handle =
+ (PhoneAccountHandle) mPhoneAccountRegisteredLatch.getArgs(0)[0];
+ assertEquals(TEST_PHONE_ACCOUNT_HANDLE, handle);
+
+ mTelecomManager.unregisterPhoneAccount(TEST_PHONE_ACCOUNT_HANDLE);
+ mPhoneAccountUnRegisteredLatch.waitForCount(1);
+ PhoneAccountHandle handle2 =
+ (PhoneAccountHandle) mPhoneAccountUnRegisteredLatch.getArgs(0)[0];
+ assertEquals(TEST_PHONE_ACCOUNT_HANDLE, handle2);
+ } finally {
+ TestUtils.setDefaultDialer(getInstrumentation(), previousDefaultDialer);
+ }
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/RttOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/RttOperationsTest.java
new file mode 100644
index 0000000..a11079f
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/RttOperationsTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017 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.telecom.cts;
+
+import android.os.Bundle;
+import android.telecom.Call;
+import android.telecom.Connection;
+import android.telecom.TelecomManager;
+
+import java.io.IOException;
+
+public class RttOperationsTest extends BaseTelecomTestWithMockServices {
+ private static final int RTT_SEND_TIMEOUT_MILLIS = 1000;
+ private static final String[] TEST_STRINGS = {
+ "A",
+ "AB",
+ "ABCDEFG",
+ "お疲れ様でした",
+ "😂😂😂💯"
+ };
+ private static final int RTT_FAILURE_REASON = 2;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (mShouldTestTelecom) {
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+ }
+ }
+
+ public void testOutgoingRttCall() throws Exception {
+ placeRttCall(false);
+ final MockConnection connection = verifyConnectionForOutgoingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ verifyRttEnabled(call, connection);
+ }
+
+ public void testIncomingRttCall() throws Exception {
+ placeRttCall(true);
+ final MockConnection connection = verifyConnectionForIncomingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ verifyRttEnabled(call, connection);
+ }
+
+ public void testLocalRttUpgradeAccepted() throws Exception {
+ placeAndVerifyCall();
+ final MockConnection connection = verifyConnectionForOutgoingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+ verifyRttDisabled(call);
+
+ TestUtils.InvokeCounter startRttCounter =
+ connection.getInvokeCounter(MockConnection.ON_START_RTT);
+ call.sendRttRequest();
+ startRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+
+ connection.setRttTextStream((Connection.RttTextStream) startRttCounter.getArgs(0)[0]);
+ connection.sendRttInitiationSuccess();
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ verifyRttEnabled(call, connection);
+ }
+
+ public void testLocalRttUpgradeRejected() throws Exception {
+ placeAndVerifyCall();
+ final MockConnection connection = verifyConnectionForOutgoingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+ verifyRttDisabled(call);
+
+ TestUtils.InvokeCounter startRttCounter =
+ connection.getInvokeCounter(MockConnection.ON_START_RTT);
+ call.sendRttRequest();
+ startRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+
+ connection.sendRttInitiationFailure(RTT_FAILURE_REASON);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ mOnRttInitiationFailedCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ assertEquals(call, mOnRttInitiationFailedCounter.getArgs(0)[0]);
+ assertEquals(RTT_FAILURE_REASON, mOnRttInitiationFailedCounter.getArgs(0)[1]);
+ verifyRttDisabled(call);
+ }
+
+ public void testAcceptRemoteRttUpgrade() throws Exception {
+ placeAndVerifyCall();
+ final MockConnection connection = verifyConnectionForOutgoingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+ verifyRttDisabled(call);
+
+ TestUtils.InvokeCounter rttRequestResponseCounter =
+ connection.getInvokeCounter(MockConnection.ON_RTT_REQUEST_RESPONSE);
+ connection.sendRemoteRttRequest();
+ mOnRttRequestCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ int requestId = (Integer) mOnRttRequestCounter.getArgs(0)[1];
+ call.respondToRttRequest(requestId, true /* accept */);
+
+ rttRequestResponseCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ verifyRttEnabled(call, connection);
+ }
+
+ public void testRejectRemoteRttRequest() throws Exception {
+ placeAndVerifyCall();
+ final MockConnection connection = verifyConnectionForOutgoingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+ verifyRttDisabled(call);
+
+ TestUtils.InvokeCounter rttRequestResponseCounter =
+ connection.getInvokeCounter(MockConnection.ON_RTT_REQUEST_RESPONSE);
+ connection.sendRemoteRttRequest();
+ mOnRttRequestCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ int requestId = (Integer) mOnRttRequestCounter.getArgs(0)[1];
+ call.respondToRttRequest(requestId, false /* accept */);
+
+ rttRequestResponseCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ assertNull(rttRequestResponseCounter.getArgs(0)[0]);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ verifyRttDisabled(call);
+ }
+
+ public void testLocalRttTermination() throws Exception {
+ placeRttCall(false);
+ final MockConnection connection = verifyConnectionForOutgoingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+
+ // Skipping RTT verification since that's tested by another test
+ TestUtils.InvokeCounter stopRttCounter =
+ connection.getInvokeCounter(MockConnection.ON_STOP_RTT);
+ call.stopRtt();
+ stopRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ verifyRttDisabled(call);
+ }
+
+ public void testRemoteRttTermination() throws Exception {
+ placeRttCall(false);
+ final MockConnection connection = verifyConnectionForOutgoingCall();
+ final MockInCallService inCallService = mInCallCallbacks.getService();
+ final Call call = inCallService.getLastCall();
+
+ // Skipping RTT verification since that's tested by another test
+ connection.sendRttSessionRemotelyTerminated();
+ TestUtils.InvokeCounter stopRttCounter =
+ connection.getInvokeCounter(MockConnection.ON_STOP_RTT);
+ call.stopRtt();
+ stopRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ verifyRttDisabled(call);
+ }
+
+ private void verifyRttDisabled(Call call) {
+ TestUtils.waitOnLocalMainLooper(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ assertFalse(call.isRttActive());
+ assertNull(call.getRttCall());
+ }
+
+ private void verifyRttEnabled(Call call, MockConnection connection) {
+ TestUtils.waitOnLocalMainLooper(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ Connection.RttTextStream connectionSideRtt = connection.getRttTextStream();
+ Call.RttCall inCallSideRtt = call.getRttCall();
+ assertNotNull(connectionSideRtt);
+ assertTrue(call.isRttActive());
+ assertNotNull(inCallSideRtt);
+
+ verifyRttPipeIntegrity(inCallSideRtt, connectionSideRtt);
+ }
+
+ private void verifyRttPipeIntegrity(Call.RttCall inCallSide, Connection.RttTextStream
+ connectionSide) {
+ for (String s : TEST_STRINGS) {
+ try {
+ inCallSide.write(s);
+ waitUntilConditionIsTrueOrTimeout(new Condition() {
+ String readSoFar = "";
+ @Override
+ public Object expected() {
+ return s;
+ }
+
+ @Override
+ public Object actual() {
+ try {
+ String newRead = connectionSide.readImmediately();
+ if (newRead != null) {
+ readSoFar += newRead;
+ }
+ return readSoFar;
+ } catch (IOException e) {
+ fail("IOException while reading from connection side");
+ return null;
+ }
+ }
+ }, RTT_SEND_TIMEOUT_MILLIS, String.format("%s failed to send correctly.", s));
+
+ connectionSide.write(s);
+ waitUntilConditionIsTrueOrTimeout(new Condition() {
+ String readSoFar = "";
+ @Override
+ public Object expected() {
+ return s;
+ }
+
+ @Override
+ public Object actual() {
+ try {
+ String newRead = inCallSide.readImmediately();
+ if (newRead != null) {
+ readSoFar += newRead;
+ }
+ return readSoFar;
+ } catch (IOException e) {
+ fail("IOException while reading from incall side");
+ return null;
+ }
+ }
+ }, RTT_SEND_TIMEOUT_MILLIS, String.format("%s failed to send correctly.", s));
+ } catch (IOException e) {
+ fail(String.format(
+ "Caught IOException when verifying %s", s));
+ }
+
+ }
+ }
+ private void placeRttCall(boolean incoming) {
+ Bundle extras = new Bundle();
+ extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true);
+ if (incoming) {
+ addAndVerifyNewIncomingCall(createTestNumber(), extras);
+ } else {
+ Bundle outgoingCallExtras = new Bundle();
+ outgoingCallExtras.putParcelable(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
+ placeAndVerifyCall(outgoingCallExtras);
+ }
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index eea7284..5c67190 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -25,6 +25,8 @@
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
@@ -79,6 +81,7 @@
.setSubscriptionAddress(Uri.parse("tel:555-TEST"))
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_VIDEO_CALLING |
+ PhoneAccount.CAPABILITY_RTT |
PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
.setHighlightColor(Color.RED)
.setShortDescription(ACCOUNT_LABEL)
@@ -170,6 +173,19 @@
executeShellCommand(instrumentation, COMMAND_WAIT_ON_HANDLERS);
}
+ public static void waitOnLocalMainLooper(long timeoutMs) {
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ final CountDownLatch lock = new CountDownLatch(1);
+ mainHandler.post(lock::countDown);
+ while (lock.getCount() > 0) {
+ try {
+ lock.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ }
+
/**
* Executes the given shell command and returns the output in a string. Note that even
* if we don't care about the output, we have to read the stream completely to make the
diff --git a/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
index 2957f43..a1423af 100644
--- a/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
@@ -189,6 +189,10 @@
int bsic = gsm.getCellIdentity().getBsic();
// TODO(b/32774471) - Bsic should always be valid
//assertTrue("getBsic() out of range [0,63]", bsic >=0 && bsic <=63);
+
+ int ta = gsm.getCellSignalStrength().getTimingAdvance();
+ assertTrue("getTimingAdvance() out of range [0,219] | Integer.MAX_VALUE, ta=" + ta,
+ ta == Integer.MAX_VALUE || (ta >= 0 && ta <= 219));
}
// Rssi(in dbm) should be within [MIN_RSSI, MAX_RSSI].
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 15249c3..3b06461 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -76,7 +76,7 @@
if [ -z ${CTS_ROOT} ]; then
# assume we're in an extracted cts install
- CTS_ROOT="$(dirname $0)/../.."
+ CTS_ROOT="$(dirname $(readlink -e $0))/../.."
fi;
JAR_DIR=${CTS_ROOT}/android-cts/tools
diff --git a/tools/utils/monsoon.py b/tools/utils/monsoon.py
index f3d63c5..d13cf3a 100755
--- a/tools/utils/monsoon.py
+++ b/tools/utils/monsoon.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.6
+#!/usr/bin/python
# Copyright (C) 2014 The Android Open Source Project
#
@@ -23,16 +23,25 @@
Example usages:
Set the voltage of the device 7536 to 4.0V
- python2.6 monsoon.py --voltage=4.0 --serialno 7536
+ python monsoon.py --voltage=4.0 --serialno 7536
Get 5000hz data from device number 7536, with unlimited number of samples
- python2.6 monsoon.py --samples -1 --hz 5000 --serialno 7536
+ python monsoon.py --samples -1 --hz 5000 --serialno 7536
Get 200Hz data for 5 seconds (1000 events) from default device
- python2.6 monsoon.py --samples 100 --hz 200
+ python monsoon.py --samples 100 --hz 200
Get unlimited 200Hz data from device attached at /dev/ttyACM0
- python2.6 monsoon.py --samples -1 --hz 200 --device /dev/ttyACM0
+ python monsoon.py --samples -1 --hz 200 --device /dev/ttyACM0
+
+Output columns for collection with --samples, separated by space:
+
+ TIMESTAMP OUTPUT OUTPUT_AVG USB USB_AVG
+ | | | |
+ | | | ` (if --includeusb and --avg)
+ | | ` (if --includeusb)
+ | ` (if --avg)
+ ` (if --timestamp)
"""
import fcntl
@@ -232,13 +241,18 @@
print >>sys.stderr, "waiting for calibration, dropped data packet"
continue
- out = []
- for main, usb, aux, voltage in data:
- if main & 1:
- out.append(((main & ~1) - self._coarse_zero) * self._coarse_scale)
+ def scale(val):
+ if val & 1:
+ return ((val & ~1) - self._coarse_zero) * self._coarse_scale
else:
- out.append((main - self._fine_zero) * self._fine_scale)
- return out
+ return (val - self._fine_zero) * self._fine_scale
+
+ out_main = []
+ out_usb = []
+ for main, usb, aux, voltage in data:
+ out_main.append(scale(main))
+ out_usb.append(scale(usb))
+ return (out_main, out_usb)
elif type == 1:
self._fine_zero = data[0][0]
@@ -317,6 +331,11 @@
print FLAGS.MainModuleHelp()
return
+ if FLAGS.includeusb:
+ num_channels = 2
+ else:
+ num_channels = 1
+
if FLAGS.avg and FLAGS.avg < 0:
print "--avg must be greater than 0"
return
@@ -359,39 +378,50 @@
# 'offset' = (consumed samples) * FLAGS.hz - (emitted samples) * native_hz
# This is the error accumulator in a variation of Bresenham's algorithm.
emitted = offset = 0
- collected = []
- history_deque = collections.deque() # past n samples for rolling average
+ chan_buffers = tuple([] for _ in range(num_channels))
+ # past n samples for rolling average
+ history_deques = tuple(collections.deque() for _ in range(num_channels))
try:
last_flush = time.time()
while emitted < FLAGS.samples or FLAGS.samples == -1:
# The number of raw samples to consume before emitting the next output
need = (native_hz - offset + FLAGS.hz - 1) / FLAGS.hz
- if need > len(collected): # still need more input samples
- samples = mon.CollectData()
- if not samples: break
- collected.extend(samples)
+ if need > len(chan_buffers[0]): # still need more input samples
+ chans_samples = mon.CollectData()
+ if not all(chans_samples): break
+ for chan_buffer, chan_samples in zip(chan_buffers, chans_samples):
+ chan_buffer.extend(chan_samples)
else:
# Have enough data, generate output samples.
# Adjust for consuming 'need' input samples.
offset += need * FLAGS.hz
while offset >= native_hz: # maybe multiple, if FLAGS.hz > native_hz
- this_sample = sum(collected[:need]) / need
+ this_sample = [sum(chan[:need]) / need for chan in chan_buffers]
if FLAGS.timestamp: print int(time.time()),
if FLAGS.avg:
- history_deque.appendleft(this_sample)
- if len(history_deque) > FLAGS.avg: history_deque.pop()
- print "%f %f" % (this_sample,
- sum(history_deque) / len(history_deque))
+ chan_avgs = []
+ for chan_deque, chan_sample in zip(history_deques, this_sample):
+ chan_deque.appendleft(chan_sample)
+ if len(chan_deque) > FLAGS.avg: chan_deque.pop()
+ chan_avgs.append(sum(chan_deque) / len(chan_deque))
+ # Interleave channel rolling avgs with latest channel data
+ data_to_print = [datum
+ for pair in zip(this_sample, chan_avgs)
+ for datum in pair]
else:
- print "%f" % this_sample
+ data_to_print = this_sample
+
+ fmt = ' '.join('%f' for _ in data_to_print)
+ print fmt % tuple(data_to_print)
+
sys.stdout.flush()
offset -= native_hz
emitted += 1 # adjust for emitting 1 output sample
- collected = collected[need:]
+ chan_buffers = tuple(c[need:] for c in chan_buffers)
now = time.time()
if now - last_flush >= 0.99: # flush every second
sys.stdout.flush()
@@ -410,7 +440,9 @@
flags.DEFINE_float("voltage", None, "Set output voltage (0 for off)")
flags.DEFINE_float("current", None, "Set max output current")
flags.DEFINE_string("usbpassthrough", None, "USB control (on, off, auto)")
- flags.DEFINE_integer("samples", None, "Collect and print this many samples")
+ flags.DEFINE_integer("samples", None,
+ "Collect and print this many samples. "
+ "-1 means collect indefinitely.")
flags.DEFINE_integer("hz", 5000, "Print this many samples/sec")
flags.DEFINE_string("device", None,
"Path to the device in /dev/... (ex:/dev/ttyACM1)")
@@ -418,5 +450,6 @@
flags.DEFINE_boolean("timestamp", None,
"Also print integer (seconds) timestamp on each line")
flags.DEFINE_boolean("ramp", True, "Gradually increase voltage")
+ flags.DEFINE_boolean("includeusb", False, "Include measurements from USB channel")
main(FLAGS(sys.argv))