Merge "autofill cts: fix tests for ATV and sync to latest ATV UX" into pi-dev
diff --git a/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py b/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py
index bb91c9a..a626ee4 100644
--- a/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py
+++ b/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py
@@ -18,7 +18,7 @@
import its.target
AE_FRAMES_PER_ITERATION = 8
-AE_CONVERGE_ITERATIONS = 3
+AE_CONVERGE_ITERATIONS = 5
# AE must converge within this number of auto requests under scene1
THRESH_AE_CONVERGE = AE_FRAMES_PER_ITERATION * AE_CONVERGE_ITERATIONS
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
index 6c00d08..1f8b024 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
@@ -73,7 +73,7 @@
public CompatibilityTestSuite() {
try {
OptionSetter setter = new OptionSetter(this);
- setter.setOptionValue("config-patterns", ".*.config");
+ setter.setOptionValue("config-patterns", ".*\\.config");
setter.setOptionValue("skip-loading-config-jar", "true");
} catch (ConfigurationException e) {
// Should not happen
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java
index 5b17a74..a46e83b 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java
@@ -44,6 +44,7 @@
@Override
public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri,
String suggestedAlias) {
+ super.onChoosePrivateKeyAlias(context, intent, uid, uri, suggestedAlias);
if (uid != Process.myUid() || uri == null) {
return null;
}
@@ -52,32 +53,38 @@
@Override
public void onUserAdded(Context context, Intent intent, UserHandle userHandle) {
+ super.onUserAdded(context, intent, userHandle);
sendUserBroadcast(context, ACTION_USER_ADDED, userHandle);
}
@Override
public void onUserRemoved(Context context, Intent intent, UserHandle userHandle) {
+ super.onUserRemoved(context, intent, userHandle);
sendUserBroadcast(context, ACTION_USER_REMOVED, userHandle);
}
@Override
public void onUserStarted(Context context, Intent intent, UserHandle userHandle) {
+ super.onUserStarted(context, intent, userHandle);
sendUserBroadcast(context, ACTION_USER_STARTED, userHandle);
}
@Override
public void onUserStopped(Context context, Intent intent, UserHandle userHandle) {
+ super.onUserStopped(context, intent, userHandle);
sendUserBroadcast(context, ACTION_USER_STOPPED, userHandle);
}
@Override
public void onUserSwitched(Context context, Intent intent, UserHandle userHandle) {
+ super.onUserSwitched(context, intent, userHandle);
sendUserBroadcast(context, ACTION_USER_SWITCHED, userHandle);
}
@Override
public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
int networkLogsCount) {
+ super.onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
// send the broadcast, the rest of the test happens in NetworkLoggingTest
Intent batchIntent = new Intent(ACTION_NETWORK_LOGS_AVAILABLE);
batchIntent.putExtra(EXTRA_NETWORK_LOGS_BATCH_TOKEN, batchToken);
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserSessionTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserSessionTest.java
new file mode 100644
index 0000000..e86d202
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserSessionTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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.deviceowner;
+
+/** Test for user session APIs. */
+public class UserSessionTest extends BaseDeviceOwnerTest {
+
+ private static final String START_SESSION_MESSAGE = "Start session";
+ private static final String END_SESSION_MESSAGE = "End session";
+
+ public void testSetLogoutEnabled() {
+ mDevicePolicyManager.setLogoutEnabled(getWho(), true);
+ assertTrue(mDevicePolicyManager.isLogoutEnabled());
+ }
+
+ public void testSetLogoutDisabled() {
+ mDevicePolicyManager.setLogoutEnabled(getWho(), false);
+ assertFalse(mDevicePolicyManager.isLogoutEnabled());
+ }
+
+ public void testSetStartUserSessionMessage() {
+ mDevicePolicyManager.setStartUserSessionMessage(getWho(), START_SESSION_MESSAGE);
+ assertEquals(START_SESSION_MESSAGE,
+ mDevicePolicyManager.getStartUserSessionMessage(getWho()));
+ }
+
+ public void testSetEndUserSessionMessage() {
+ mDevicePolicyManager.setEndUserSessionMessage(getWho(), END_SESSION_MESSAGE);
+ assertEquals(END_SESSION_MESSAGE, mDevicePolicyManager.getEndUserSessionMessage(getWho()));
+ }
+
+ public void testClearStartUserSessionMessage() {
+ mDevicePolicyManager.setStartUserSessionMessage(getWho(), START_SESSION_MESSAGE);
+ mDevicePolicyManager.setStartUserSessionMessage(getWho(), null);
+ assertNull(mDevicePolicyManager.getStartUserSessionMessage(getWho()));
+ }
+
+
+ public void testClearEndUserSessionMessage() {
+ mDevicePolicyManager.setEndUserSessionMessage(getWho(), END_SESSION_MESSAGE);
+ mDevicePolicyManager.setEndUserSessionMessage(getWho(), null);
+ assertNull(mDevicePolicyManager.getEndUserSessionMessage(getWho()));
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index f9f1fce..25627ee 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -494,6 +494,13 @@
}
}
+ public void testUserSession() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ executeDeviceOwnerTest("UserSessionTest");
+ }
+
public void testSecurityLoggingWithTwoUsers() throws Exception {
if (!mHasFeature || !canCreateAdditionalUsers(1)) {
return;
diff --git a/hostsidetests/incident/src/com/android/server/cts/IncidentdIsolatedTest.java b/hostsidetests/incident/src/com/android/server/cts/IncidentdIsolatedTest.java
index e4f5176..98e4b7a 100644
--- a/hostsidetests/incident/src/com/android/server/cts/IncidentdIsolatedTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/IncidentdIsolatedTest.java
@@ -34,7 +34,7 @@
if (execCommandAndFind(CMD_TOP, SYSTEM_SERVER) != null) {
CLog.logAndDisplay(LogLevel.INFO, "stop server");
getDevice().executeShellCommand("stop");
- Thread.sleep(3000); // wait for 3 seconds to stop.
+ Thread.sleep(10000); // wait for 10 seconds to stop.
assertTrue("system_server failed to stop",
!execCommandAndGet(CMD_TOP).contains(SYSTEM_SERVER));
}
diff --git a/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java b/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java
index a3751f5..c62d85e 100644
--- a/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/IncidentdTest.java
@@ -27,7 +27,7 @@
final String destArg = dest == null || dest.isEmpty() ? "" : "-p " + dest;
final IncidentProto dump = getDump(IncidentProto.parser(), "incident " + destArg + " 2>/dev/null");
- SystemPropertiesTest.verifySystemPropertiesProto(dump.getSystemProperties(), filterLevel, mCtsBuild);
+ SystemPropertiesTest.verifySystemPropertiesProto(dump.getSystemProperties(), filterLevel);
StackTraceIncidentTest.verifyBackTraceProto(dump.getNativeTraces(), filterLevel);
StackTraceIncidentTest.verifyBackTraceProto(dump.getHalTraces(), filterLevel);
diff --git a/hostsidetests/incident/src/com/android/server/cts/SystemPropertiesTest.java b/hostsidetests/incident/src/com/android/server/cts/SystemPropertiesTest.java
index 28e1886..8dc4722 100644
--- a/hostsidetests/incident/src/com/android/server/cts/SystemPropertiesTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/SystemPropertiesTest.java
@@ -24,18 +24,16 @@
public class SystemPropertiesTest extends ProtoDumpTestCase {
private static final String TAG = "SystemPropertiesTest";
- static void verifySystemPropertiesProto(SystemPropertiesProto properties,
- final int filterLevel, IBuildInfo ctsBuild) {
+ static void verifySystemPropertiesProto(SystemPropertiesProto properties, final int filterLevel) {
// check local tagged field
if (filterLevel == PRIVACY_LOCAL) {
assertTrue(properties.getExtraPropertiesCount() > 0);
} else {
assertEquals(0, properties.getExtraPropertiesCount());
}
- // check explicit tagged field
- assertEquals(filterLevel == PRIVACY_AUTO, properties.getDalvikVm().getHeapmaxfree().isEmpty());
- // check automatic tagged field
- assertEquals(ctsBuild.getBuildId(),
- properties.getRo().getBuild().getVersion().getIncremental());
+ // check explicit tagged field, persist.sys.timezone is public prop.
+ assertEquals(filterLevel == PRIVACY_AUTO, properties.getPersist().getSysTimezone().isEmpty());
+ // check automatic tagged field, ro.build.display.id is public prop.
+ assertFalse(properties.getRo().getBuild().getDisplayId().isEmpty());
}
}
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index d03fc17..e25b96c 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -55,6 +55,7 @@
$(HOST_OUT_EXECUTABLES)/checkfc \
$(HOST_OUT_EXECUTABLES)/property_info_checker \
$(HOST_OUT_EXECUTABLES)/searchpolicy \
+ $(HOST_OUT_EXECUTABLES)/secilc \
$(HOST_OUT_EXECUTABLES)/sepolicy_tests \
$(HOST_OUT_EXECUTABLES)/treble_sepolicy_tests \
$(HOST_OUT)/lib64/libsepolwrap.$(SHAREDLIB_EXT) \
diff --git a/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java b/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java
index d878342..2e0d0a5 100644
--- a/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java
+++ b/hostsidetests/security/src/android/cts/security/FileSystemPermissionTest.java
@@ -73,8 +73,8 @@
public void testDevHwRandomPermissions() throws Exception {
// This test asserts that, if present, /dev/hw_random must:
- // 1. Be owned by UID root and GID system
- // 2. Have file permissions 0440 (only readable, and only by owner and group). The reason
+ // 1. Be owned by UID root
+ // 2. Not allow any world read, write, or execute permissions. The reason
// for being not readable by all/other is to avoid apps reading from this device.
// Firstly, /dev/hw_random is not public API for apps. Secondly, apps might erroneously
// use the output of Hardware RNG as trusted random output. Android does not trust output
@@ -96,9 +96,9 @@
fail("Unexpected output from " + command + ": \"" + output + "\"");
}
String[] outputWords = output.split("\\s");
- assertEquals("Wrong file mode on " + HW_RNG_DEVICE, "cr--r-----", outputWords[0]);
+ assertEquals("Wrong device type on " + HW_RNG_DEVICE, "c", outputWords[0].substring(0, 1));
+ assertEquals("Wrong world file mode on " + HW_RNG_DEVICE, "---", outputWords[0].substring(7));
assertEquals("Wrong owner of " + HW_RNG_DEVICE, "root", outputWords[2]);
- assertEquals("Wrong group of " + HW_RNG_DEVICE, "system", outputWords[3]);
assertEquals("Wrong device major on " + HW_RNG_DEVICE, "10,", outputWords[4]);
assertEquals("Wrong device minor on " + HW_RNG_DEVICE, "183", outputWords[5]);
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 8428758..6cada58 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -52,6 +52,11 @@
import java.util.Scanner;
import java.util.Set;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
/**
* Host-side SELinux tests.
*
@@ -64,6 +69,8 @@
private static final Map<ITestDevice, File> cachedDevicePolicyFiles = new HashMap<>(1);
private static final Map<ITestDevice, File> cachedDevicePlatFcFiles = new HashMap<>(1);
private static final Map<ITestDevice, File> cachedDeviceNonplatFcFiles = new HashMap<>(1);
+ private static final Map<ITestDevice, File> cachedDeviceVendorManifest = new HashMap<>(1);
+ private static final Map<ITestDevice, File> cachedDeviceSystemPolicy = new HashMap<>(1);
private File sepolicyAnalyze;
private File checkSeapp;
@@ -191,6 +198,54 @@
return file;
}
+ private static File buildSystemPolicy(ITestDevice device, Map<ITestDevice, File> cache,
+ String tmpFileName) throws Exception {
+ File builtPolicyFile;
+ synchronized (cache) {
+ builtPolicyFile = cache.get(device);
+ }
+ if (builtPolicyFile != null) {
+ return builtPolicyFile;
+ }
+
+
+ builtPolicyFile = File.createTempFile(tmpFileName, ".tmp");
+ builtPolicyFile.deleteOnExit();
+
+ File secilc = copyResourceToTempFile("/secilc");
+ secilc.setExecutable(true);
+
+ File systemSepolicyCilFile = File.createTempFile("plat_sepolicy", ".cil");
+ systemSepolicyCilFile.deleteOnExit();
+
+ if (!device.pullFile("/system/etc/selinux/plat_sepolicy.cil", systemSepolicyCilFile)) {
+ device.pullFile("/plat_sepolicy.cil", systemSepolicyCilFile);
+ }
+
+ ProcessBuilder pb = new ProcessBuilder(
+ secilc.getAbsolutePath(),
+ "-m", "-M", "true", "-c", "30",
+ "-o", builtPolicyFile.getAbsolutePath(),
+ systemSepolicyCilFile.getAbsolutePath());
+ pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+ pb.redirectErrorStream(true);
+ Process p = pb.start();
+ p.waitFor();
+ BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ String line;
+ StringBuilder errorString = new StringBuilder();
+ while ((line = result.readLine()) != null) {
+ errorString.append(line);
+ errorString.append("\n");
+ }
+ assertTrue(errorString.toString(), errorString.length() == 0);
+
+ synchronized (cache) {
+ cache.put(device, builtPolicyFile);
+ }
+ return builtPolicyFile;
+ }
+
// NOTE: cts/tools/selinux depends on this method. Rename/change with caution.
/**
* Returns the host-side file containing the SELinux policy of the device under test.
@@ -199,6 +254,37 @@
return getDeviceFile(device, cachedDevicePolicyFiles, "/sys/fs/selinux/policy", "sepolicy");
}
+ // NOTE: cts/tools/selinux depends on this method. Rename/change with caution.
+ /**
+ * Returns the host-side file containing the system SELinux policy of the device under test.
+ */
+ public static File getDeviceSystemPolicyFile(ITestDevice device) throws Exception {
+ return buildSystemPolicy(device, cachedDeviceSystemPolicy, "system_sepolicy");
+ }
+
+ // NOTE: cts/tools/selinux depends on this method. Rename/change with caution.
+ /**
+ * Returns the major number of sepolicy version of device's vendor implementation.
+ * TODO(b/37999212): Use VINTF object API instead of parsing vendor manifest.
+ */
+ public static int getVendorSepolicyVersion(ITestDevice device) throws Exception {
+ String deviceManifestPath =
+ (device.doesFileExist("/vendor/etc/vintf/manifest.xml")) ?
+ "/vendor/etc/vintf/manifest.xml" :
+ "/vendor/manifest.xml";
+ File vendorManifestFile = getDeviceFile(device, cachedDeviceVendorManifest,
+ deviceManifestPath, "manifest.xml");
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(vendorManifestFile);
+ Element root = doc.getDocumentElement();
+ Element sepolicy = (Element) root.getElementsByTagName("sepolicy").item(0);
+ Element version = (Element) sepolicy.getElementsByTagName("version").item(0);
+ String sepolicyVersion = version.getTextContent().split("\\.")[0];
+ return Integer.parseInt(sepolicyVersion);
+ }
+
/**
* Tests that the kernel is enforcing selinux policy globally.
*
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 71d600a..809d682 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertTrue;
import android.os.WakeLockLevelEnum;
+import android.platform.test.annotations.RestrictedBuildTest;
import com.android.internal.os.StatsdConfigProto.FieldMatcher;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
@@ -228,6 +229,7 @@
assertTrue("found uid " + uid, found);
}
+ @RestrictedBuildTest
public void testCpuTimePerUidFreq() throws Exception {
StatsdConfig.Builder config = getPulledConfig();
FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
index 75a73f2..b968811 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
@@ -29,6 +29,7 @@
private static final int CANCEL_JOB_ID = TimingConstraintsTest.class.hashCode() + 1;
private static final int EXPIRED_JOB_ID = TimingConstraintsTest.class.hashCode() + 2;
private static final int UNEXPIRED_JOB_ID = TimingConstraintsTest.class.hashCode() + 3;
+ private static final int ZERO_DELAY_JOB_ID = TimingConstraintsTest.class.hashCode() + 4;
public void testScheduleOnce() throws Exception {
JobInfo oneTimeJob = new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
@@ -45,6 +46,7 @@
JobInfo cancelJob = new JobInfo.Builder(CANCEL_JOB_ID, kJobServiceComponent)
.setMinimumLatency(5000L) // make sure it doesn't actually run immediately
.setOverrideDeadline(7000L)
+ .setRequiresDeviceIdle(true)
.build();
kTestEnvironment.setExpectedExecutions(0);
@@ -55,6 +57,19 @@
kTestEnvironment.awaitTimeout());
}
+ public void testExplicitZeroLatency() throws Exception {
+ JobInfo job = new JobInfo.Builder(ZERO_DELAY_JOB_ID, kJobServiceComponent)
+ .setMinimumLatency(0L)
+ .setRequiresDeviceIdle(true)
+ .setOverrideDeadline(10_000L)
+ .build();
+ kTestEnvironment.setExpectedExecutions(1);
+ mJobScheduler.schedule(job);
+ final boolean executed = kTestEnvironment.awaitExecution();
+ assertTrue("Failed to execute job with explicit zero min latency",
+ kTestEnvironment.awaitExecution());
+ }
+
/**
* Ensure that when a job is executed because its deadline has expired, that
* {@link JobParameters#isOverrideDeadlineExpired()} returns the correct value.
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index 50a8bcc..720a4e0 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -187,6 +187,18 @@
assertTrue(TextUtils.equals(originalText, info.getContentDescription()));
}
+ @SmallTest
+ public void testIsHeadingTakesOldApiIntoAccount() {
+ final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ assertFalse(info.isHeading());
+ final CollectionItemInfo headingItemInfo = CollectionItemInfo.obtain(0, 1, 0, 1, true);
+ info.setCollectionItemInfo(headingItemInfo);
+ assertTrue(info.isHeading());
+ final CollectionItemInfo nonHeadingItemInfo = CollectionItemInfo.obtain(0, 1, 0, 1, false);
+ info.setCollectionItemInfo(nonHeadingItemInfo);
+ assertFalse(info.isHeading());
+ }
+
/**
* Fully populates the {@link AccessibilityNodeInfo} to marshal.
*
diff --git a/tests/autofillservice/res/layout/fat_activity.xml b/tests/autofillservice/res/layout/fat_activity.xml
index 9b4a8b6..2efd33c 100644
--- a/tests/autofillservice/res/layout/fat_activity.xml
+++ b/tests/autofillservice/res/layout/fat_activity.xml
@@ -17,6 +17,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/root"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:focusable="true"
@@ -136,10 +137,10 @@
</LinearLayout>
- <View
+ <view class="android.autofillservice.cts.FatActivity$MyView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autofillHints="importantAmI">
- </View>
+ </view>
</LinearLayout>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FatActivity.java b/tests/autofillservice/src/android/autofillservice/cts/FatActivity.java
index b3e064e..8a53f4a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FatActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FatActivity.java
@@ -25,10 +25,13 @@
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
import android.os.Bundle;
+import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
+import android.widget.LinearLayout;
/**
* An activity containing mostly widgets that should be removed from an auto-fill structure to
@@ -41,6 +44,7 @@
static final String ID_INPUT_CONTAINER = "input_container";
static final String ID_IMAGE = "image";
static final String ID_IMPORTANT_IMAGE = "important_image";
+ static final String ID_ROOT = "root";
static final String ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS =
"not_important_container_excluding_descendants";
@@ -63,6 +67,7 @@
static final String ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD =
"not_important_container_mixed_descendants_grand_child";
+ private LinearLayout mRoot;
private EditText mCaptcha;
private EditText mInput;
private ImageView mImage;
@@ -80,7 +85,7 @@
private View mNotImportantContainerMixedDescendantsChild;
private View mNotImportantContainerMixedDescendantsGrandChild;
- private View mViewWithAutofillHints;
+ private MyView mViewWithAutofillHints;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -88,6 +93,7 @@
setContentView(R.layout.fat_activity);
+ mRoot = findViewById(R.id.root);
mCaptcha = findViewById(R.id.captcha);
mInput = findViewById(R.id.input);
mImage = findViewById(R.id.image);
@@ -114,10 +120,11 @@
mNotImportantContainerMixedDescendantsGrandChild = findViewById(
R.id.not_important_container_mixed_descendants_grand_child);
- mViewWithAutofillHints = findViewByAutofillHint(this, "importantAmI");
+ mViewWithAutofillHints = (MyView) findViewByAutofillHint(this, "importantAmI");
assertThat(mViewWithAutofillHints).isNotNull();
// Sanity check for importantForAutofill modes
+ assertThat(mRoot.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_AUTO);
assertThat(mInput.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_YES);
assertThat(mCaptcha.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_NO);
assertThat(mImage.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_NO);
@@ -157,4 +164,18 @@
v.visit(mInput);
});
}
+
+ /**
+ * Custom view that defines an autofill type so autofill hints are set on {@code ViewNode}.
+ */
+ public static class MyView extends View {
+ public MyView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public int getAutofillType() {
+ return AUTOFILL_TYPE_TEXT;
+ }
+ }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
index 9e458fd4..28ecdf7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
@@ -30,9 +30,11 @@
import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS;
import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_CHILD;
import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD;
-import static android.autofillservice.cts.Helper.assertNumberOfChildren;
+import static android.autofillservice.cts.FatActivity.ID_ROOT;
+import static android.autofillservice.cts.Helper.findNodeByAutofillHint;
import static android.autofillservice.cts.Helper.findNodeByResourceId;
import static android.autofillservice.cts.Helper.findNodeByText;
+import static android.autofillservice.cts.Helper.getNumberNodes;
import static android.autofillservice.cts.Helper.importantForAutofillAsString;
import static android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO;
import static android.view.View.IMPORTANT_FOR_AUTOFILL_NO;
@@ -43,7 +45,6 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
@@ -61,7 +62,7 @@
new AutofillActivityTestRule<FatActivity>(FatActivity.class);
private FatActivity mFatActivity;
- private AssistStructure mStructure;
+ private ViewNode mRoot;
@Before
public void setActivity() {
@@ -69,7 +70,7 @@
}
@Test
- public void testNoContainers() throws Exception {
+ public void testAutomaticRequest() throws Exception {
// Set service.
enableService();
@@ -79,13 +80,22 @@
// Trigger auto-fill.
mFatActivity.onInput((v) -> v.requestFocus());
final FillRequest fillRequest = sReplier.getNextFillRequest();
- mStructure = fillRequest.structure;
mUiBot.assertNoDatasetsEver();
- // TODO: should only have X children, but there is an extra
- // TextView that's probably coming from the title. For now we're just ignoring it, but
- // ideally we should change the .xml to exclude it.
- assertNumberOfChildren(fillRequest.structure, 9);
+ mRoot = findNodeByResourceId(fillRequest.structure, ID_ROOT);
+ /*
+ * Should have 8 nodes:
+ *
+ * 1. root
+ * 2. important_image
+ * 3. label without id but marked as important
+ * 4. input_container
+ * 5. input
+ * 6. important_container_excluding_descendants
+ * 7. not_important_container_mixed_descendants_child
+ * 8. view (My View) without id but with hints
+ */
+ assertThat(getNumberNodes(mRoot)).isEqualTo(8);
// Should not have ImageView...
assertThat(findNodeByResourceId(fillRequest.structure, ID_IMAGE)).isNull();
@@ -108,28 +118,31 @@
assertThat(input.getIdEntry()).isEqualTo(ID_INPUT);
// Make sure a non-important container can exclude descendants
- assertThat(findNodeByResourceId(fillRequest.structure,
+ assertThat(findNodeByResourceId(mRoot,
ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS)).isNull();
- assertThat(findNodeByResourceId(fillRequest.structure,
+ assertThat(findNodeByResourceId(mRoot,
ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_CHILD)).isNull();
- assertThat(findNodeByResourceId(fillRequest.structure,
+ assertThat(findNodeByResourceId(mRoot,
ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_GRAND_CHILD)).isNull();
// Make sure an important container can exclude descendants
assertNodeExists(ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS,
IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS);
- assertThat(findNodeByResourceId(fillRequest.structure,
+ assertThat(findNodeByResourceId(mRoot,
ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_CHILD)).isNull();
- assertThat(findNodeByResourceId(fillRequest.structure,
+ assertThat(findNodeByResourceId(mRoot,
ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_GRAND_CHILD)).isNull();
// Make sure an intermediary descendant can be excluded
- assertThat(findNodeByResourceId(fillRequest.structure,
+ assertThat(findNodeByResourceId(mRoot,
ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS)).isNull();
assertNodeExists(ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_CHILD,
IMPORTANT_FOR_AUTOFILL_YES);
- assertThat(findNodeByResourceId(fillRequest.structure,
+ assertThat(findNodeByResourceId(mRoot,
ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD)).isNull();
+
+ // Make sure entry with hints is always shown
+ assertThat(findNodeByAutofillHint(mRoot, "importantAmI")).isNotNull();
}
@Test
@@ -143,13 +156,31 @@
// Trigger autofill.
mFatActivity.onInput((v) -> mFatActivity.getAutofillManager().requestAutofill(v));
final FillRequest fillRequest = sReplier.getNextFillRequest();
- mStructure = fillRequest.structure;
mUiBot.assertNoDatasetsEver();
- // TODO: should only have X children, but there is an extra
- // TextView that's probably coming from the title. For now we're just ignoring it, but
- // ideally we should change the .xml to exclude it.
- assertNumberOfChildren(fillRequest.structure, 28);
+ mRoot = findNodeByResourceId(fillRequest.structure, ID_ROOT);
+ /*
+ * Should have 18 nodes:
+ * 1. root
+ * 2. layout without id
+ * 3. label without id
+ * 4. input_container
+ * 5. input
+ * 6. captcha
+ * 7. image
+ * 8. important_image
+ * 9. not_important_container_excluding_descendants
+ * 10.not_important_container_excluding_descendants_child
+ * 11.not_important_container_excluding_descendants_grand_child
+ * 12.important_container_excluding_descendants
+ * 13.important_container_excluding_descendants_child
+ * 14.important_container_excluding_descendants_grand_child
+ * 15.not_important_container_mixed_descendants
+ * 16.not_important_container_mixed_descendants_child
+ * 17.not_important_container_mixed_descendants_grand_child
+ * 18.view (My View) without id but with hints
+ */
+ assertThat(getNumberNodes(mRoot)).isEqualTo(18);
// Assert all nodes are present
assertNodeExists(ID_IMAGE, IMPORTANT_FOR_AUTOFILL_NO);
@@ -186,15 +217,18 @@
IMPORTANT_FOR_AUTOFILL_YES);
assertNodeExists(ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD,
IMPORTANT_FOR_AUTOFILL_NO);
+ assertNode(findNodeByAutofillHint(mRoot, "importantAmI"), IMPORTANT_FOR_AUTOFILL_AUTO);
}
private ViewNode assertNodeExists(String resourceId, int expectedImportantForAutofill) {
- final ViewNode node = findNodeByResourceId(mStructure, resourceId);
+ assertWithMessage("root node not set").that(mRoot).isNotNull();
+ final ViewNode node = findNodeByResourceId(mRoot, resourceId);
+ assertWithMessage("no node with resource id '%s'", resourceId).that(node).isNotNull();
return assertNode(node, resourceId, expectedImportantForAutofill);
}
private ViewNode assertNodeWithTextExists(String text, int expectedImportantForAutofill) {
- final ViewNode node = findNodeByText(mStructure, text);
+ final ViewNode node = findNodeByText(mRoot, text);
return assertNode(node, text, expectedImportantForAutofill);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 34a2d96..0a6cfc7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -137,6 +137,10 @@
return id.equals(node.getText());
};
+ private static final NodeFilter<ViewNode> AUTOFILL_HINT_FILTER = (node, id) -> {
+ return hasHint(node.getAutofillHints(), id);
+ };
+
private static final NodeFilter<ViewNode> WEBVIEW_FORM_FILTER = (node, id) -> {
final String className = node.getClassName();
if (!className.equals("android.webkit.WebView")) return false;
@@ -315,6 +319,14 @@
}
/**
+ * Gets a node given the value of its (single) autofill hint property, or {@code null} if not
+ * found.
+ */
+ static ViewNode findNodeByAutofillHint(ViewNode node, String hint) {
+ return findNodeByFilter(node, hint, AUTOFILL_HINT_FILTER);
+ }
+
+ /**
* Gets a node given the name of its HTML INPUT tag or Android resoirce id, or {@code null} if
* not found.
*/
@@ -644,7 +656,7 @@
}
/**
- * Gets the total number of nodes in an structure, including all descendants.
+ * Gets the total number of nodes in an structure.
*/
static int getNumberNodes(AssistStructure structure) {
int count = 0;
@@ -660,7 +672,7 @@
/**
* Gets the total number of nodes in an node, including all descendants and the node itself.
*/
- private static int getNumberNodes(ViewNode node) {
+ static int getNumberNodes(ViewNode node) {
int count = 1;
final int childrenSize = node.getChildCount();
if (childrenSize > 0) {
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index 430f238..81335c0 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -358,8 +358,11 @@
blockingListenerList.add(mCameraListener);
}
} finally {
- for (CameraDevice camera : cameraList) {
- camera.close();
+ for (int i = 0; i < cameraList.size(); i++) {
+ // With conflicting devices, opening of one camera could result in the other camera
+ // being disconnected. To handle such case, reset the mock before close.
+ reset(listenerList.get(i));
+ cameraList.get(i).close();
}
for (BlockingStateCallback blockingListener : blockingListenerList) {
blockingListener.waitForState(
diff --git a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
index 488c0f3..6ca9601 100644
--- a/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/FastBasicsTest.java
@@ -102,6 +102,11 @@
assertTrue("Bad timestamps", timestamp2 > timestamp);
+ // If EnableZsl is supported, disable ZSL in order to compare preview and still timestamps.
+ if (mStaticInfo.isEnableZslSupported()) {
+ stillCaptureRequest.set(CaptureRequest.CONTROL_ENABLE_ZSL, false);
+ }
+
CaptureRequest capture = stillCaptureRequest.build();
mSession.capture(capture, resultListener, mHandler);
diff --git a/tests/framework/base/windowmanager/Android.mk b/tests/framework/base/windowmanager/Android.mk
index af34c5d..a098701 100644
--- a/tests/framework/base/windowmanager/Android.mk
+++ b/tests/framework/base/windowmanager/Android.mk
@@ -25,6 +25,8 @@
$(call all-named-files-under,Components.java, alertwindowapp) \
$(call all-named-files-under,Components.java, alertwindowappsdk25)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
LOCAL_PACKAGE_NAME := CtsWindowManagerDeviceTestCases
LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 5f08442..3168dae 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -34,7 +34,8 @@
<activity android:name="android.server.wm.AlertWindowsAppOpsTestsActivity"/>
<activity android:name="android.server.wm.DialogFrameTestActivity" />
<activity android:name="android.server.wm.DisplayCutoutTests$TestActivity" />
- <activity android:name="android.server.wm.LocationOnScreenTests$TestActivity" />
+ <activity android:name="android.server.wm.LocationOnScreenTests$TestActivity"
+ android:theme="@style/no_starting_window" />
<activity android:name="android.server.wm.LocationInWindowTests$TestActivity" />
</application>
diff --git a/tests/framework/base/windowmanager/res/values/styles.xml b/tests/framework/base/windowmanager/res/values/styles.xml
new file mode 100644
index 0000000..4e59d14
--- /dev/null
+++ b/tests/framework/base/windowmanager/res/values/styles.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2018 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.
+ -->
+
+<resources>
+ <style name="no_starting_window" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:windowDisablePreview">true</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/LocationInWindowTests.java b/tests/framework/base/windowmanager/src/android/server/wm/LocationInWindowTests.java
index 206185e..1272237 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/LocationInWindowTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/LocationInWindowTests.java
@@ -36,7 +36,6 @@
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -53,7 +52,6 @@
import org.junit.rules.ErrorCollector;
import org.junit.runner.RunWith;
-import java.util.Arrays;
import java.util.function.Supplier;
@RunWith(AndroidJUnit4.class)
@@ -80,18 +78,18 @@
}
@Test
- public void testLocationOnDisplay_appWindow() {
+ public void testLocationInWindow_appWindow() {
runTest(mLayoutParams);
}
@Test
- public void testLocationOnDisplay_appWindow_fullscreen() {
+ public void testLocationInWindow_appWindow_fullscreen() {
mLayoutParams.flags |= LayoutParams.FLAG_FULLSCREEN;
runTest(mLayoutParams);
}
@Test
- public void testLocationOnDisplay_floatingWindow() {
+ public void testLocationInWindow_floatingWindow() {
mLayoutParams.height = 100;
mLayoutParams.width = 100;
mLayoutParams.gravity = Gravity.CENTER;
@@ -100,13 +98,13 @@
}
@Test
- public void testLocationOnDisplay_appWindow_displayCutoutNever() {
+ public void testLocationInWindow_appWindow_displayCutoutNever() {
mLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
runTest(mLayoutParams);
}
@Test
- public void testLocationOnDisplay_appWindow_displayCutoutShortEdges() {
+ public void testLocationInWindow_appWindow_displayCutoutShortEdges() {
mLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
runTest(mLayoutParams);
}
@@ -116,11 +114,11 @@
PollingCheck.waitFor(() -> getOnMainSync(activity::isEnterAnimationComplete));
runOnMainSync(() -> {
- assertThatViewGetLocationInWindowAndSurfaceIsCorrect(activity.mView);
+ assertThatViewGetLocationInWindowIsCorrect(activity.mView);
});
}
- private void assertThatViewGetLocationInWindowAndSurfaceIsCorrect(View v) {
+ private void assertThatViewGetLocationInWindowIsCorrect(View v) {
final float[] expected = new float[] {0, 0};
v.getMatrix().mapPoints(expected);
@@ -147,12 +145,6 @@
return new Point(out[0], out[1]);
}
- private Point locationInSurfaceAsPoint(View v) {
- final int[] out = new int[2];
- v.getLocationInWindow(out);
- return new Point(out[0], out[1]);
- }
-
private <T> void assertThat(String reason, T actual, Matcher<? super T> matcher) {
mErrorCollector.checkThat(reason, actual, matcher);
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
index 86879ee..7645e25 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
@@ -30,14 +30,15 @@
import android.graphics.ColorSpace;
import android.graphics.ImageDecoder;
import android.os.Parcel;
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.RequiresDevice;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -781,6 +782,43 @@
}
@Test
+ public void testEncodeP3hardware() {
+ Bitmap b = null;
+ ImageDecoder.Source src = ImageDecoder.createSource(mResources.getAssets(),
+ "green-p3.png");
+ try {
+ b = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_HARDWARE);
+ });
+ assertNotNull(b);
+ assertEquals(Bitmap.Config.HARDWARE, b.getConfig());
+ assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace());
+ } catch (IOException e) {
+ fail("Failed with " + e);
+ }
+
+ for (Bitmap.CompressFormat format : new Bitmap.CompressFormat[] {
+ Bitmap.CompressFormat.JPEG,
+ Bitmap.CompressFormat.WEBP,
+ Bitmap.CompressFormat.PNG,
+ }) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ assertTrue("Failed to encode 8888 to " + format, b.compress(format, 100, out));
+
+ byte[] array = out.toByteArray();
+ src = ImageDecoder.createSource(ByteBuffer.wrap(array));
+
+ try {
+ Bitmap b2 = ImageDecoder.decodeBitmap(src);
+ assertEquals("Wrong color space for " + format,
+ ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b2.getColorSpace());
+ } catch (IOException e) {
+ fail("Failed with " + e);
+ }
+ }
+ }
+
+ @Test
@RequiresDevice // SwiftShader does not yet have support for F16 in HARDWARE b/75778024
public void test16bitHardware() {
// Decoding to HARDWARE may use LINEAR_EXTENDED_SRGB or SRGB, depending
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java
index f3c17cf..ae8b991 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java
@@ -51,13 +51,14 @@
@Override
protected void tearDown() throws Exception {
+ // try/catch for every method in case the tests left the objects in various states
if (mMp != null) {
- mMp.stop();
- mMp.release();
+ try { mMp.stop(); } catch (Exception e) {}
+ try { mMp.release(); } catch (Exception e) {}
mMp = null;
}
if (mSp != null) {
- mSp.release();
+ try { mSp.release(); } catch (Exception e) {}
mSp = null;
}
}
@@ -205,7 +206,7 @@
nbActivePlayersBeforeStart + 1/*expected*/, callback.getNbConfigs());
assertTrue("Active player, attributes not found", hasAttr(callback.getConfigs(), aa));
- // stopping recording: callback is called with no match
+ // stopping playback: callback is called with no match
callback.reset();
mMp.pause();
Thread.sleep(TEST_TIMING_TOLERANCE_MS);
@@ -215,7 +216,7 @@
assertEquals("number of active players not expected after pause",
nbActivePlayersBeforeStart/*expected*/, callback.getNbConfigs());
- // unregister callback and start recording again
+ // unregister callback and start playback again
am.unregisterAudioPlaybackCallback(callback);
Thread.sleep(TEST_TIMING_TOLERANCE_MS);
callback.reset();
@@ -235,6 +236,58 @@
}
}
+ public void testCallbackMediaPlayerRelease() throws Exception {
+ final HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ final Handler h = new Handler(handlerThread.getLooper());
+
+ try {
+ AudioManager am = new AudioManager(getContext());
+ assertNotNull("Could not create AudioManager", am);
+
+ final AudioAttributes aa = (new AudioAttributes.Builder())
+ .setUsage(TEST_USAGE)
+ .setContentType(TEST_CONTENT)
+ .build();
+
+ mMp = MediaPlayer.create(getContext(), R.raw.sine1khzs40dblong,
+ aa, am.generateAudioSessionId());
+
+ MyAudioPlaybackCallback callback = new MyAudioPlaybackCallback();
+ am.registerAudioPlaybackCallback(callback, h /*handler*/);
+
+ // query how many active players before starting the MediaPlayer
+ List<AudioPlaybackConfiguration> configs = am.getActivePlaybackConfigurations();
+ final int nbActivePlayersBeforeStart = configs.size();
+
+ mMp.start();
+ Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+
+ assertEquals("onPlaybackConfigChanged call count not expected",
+ 1/*expected*/, callback.getCbInvocationNumber()); //only one start call
+ assertEquals("number of active players not expected",
+ // one more player active
+ nbActivePlayersBeforeStart + 1/*expected*/, callback.getNbConfigs());
+ assertTrue("Active player, attributes not found", hasAttr(callback.getConfigs(), aa));
+
+ // release the player without stopping or pausing it first
+ callback.reset();
+ mMp.release();
+ Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+
+ assertEquals("onPlaybackConfigChanged call count not expected after release",
+ 1/*expected*/, callback.getCbInvocationNumber());//only release call since reset
+ assertEquals("number of active players not expected after release",
+ nbActivePlayersBeforeStart/*expected*/, callback.getNbConfigs());
+
+ am.unregisterAudioPlaybackCallback(callback);
+ } finally {
+ if (h != null) {
+ h.getLooper().quit();
+ }
+ }
+ }
+
public void testGetterSoundPool() throws Exception {
if (!isValidPlatform("testSoundPool")) return;
diff --git a/tests/tests/media/src/android/media/cts/DynamicsProcessingTest.java b/tests/tests/media/src/android/media/cts/DynamicsProcessingTest.java
index a7ad33b..60f2d21 100644
--- a/tests/tests/media/src/android/media/cts/DynamicsProcessingTest.java
+++ b/tests/tests/media/src/android/media/cts/DynamicsProcessingTest.java
@@ -24,8 +24,14 @@
import android.media.MediaPlayer;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.DynamicsProcessing;
+import android.media.audiofx.DynamicsProcessing.BandBase;
+import android.media.audiofx.DynamicsProcessing.BandStage;
import android.media.audiofx.DynamicsProcessing.Channel;
import android.media.audiofx.DynamicsProcessing.Eq;
+import android.media.audiofx.DynamicsProcessing.EqBand;
+import android.media.audiofx.DynamicsProcessing.Limiter;
+import android.media.audiofx.DynamicsProcessing.Mbc;
+import android.media.audiofx.DynamicsProcessing.MbcBand;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -35,7 +41,6 @@
private DynamicsProcessing mDP;
private static final int MIN_CHANNEL_COUNT = 1;
- private static final int TEST_CHANNEL = 0;
private static final float EPSILON = 0.00001f;
private static final int DEFAULT_VARIANT =
DynamicsProcessing.VARIANT_FAVOR_FREQUENCY_RESOLUTION;
@@ -49,6 +54,12 @@
private static final float DEFAULT_FRAME_DURATION = 9.5f;
private static final float DEFAULT_INPUT_GAIN = -12.5f;
+ private static final int TEST_CHANNEL_COUNT = 2;
+ private static final float TEST_GAIN1 = 12.1f;
+ private static final float TEST_GAIN2 = -2.8f;
+ private static final int TEST_CHANNEL_INDEX = 0;
+ private static final int TEST_BAND_INDEX = 0;
+
//-----------------------------------------------------------------
// DynamicsProcessing tests:
//----------------------------------
@@ -129,7 +140,7 @@
final int channelCount = mDP.getChannelCount();
assertTrue("unexpected channel count", channelCount >= MIN_CHANNEL_COUNT);
- Channel channel = mDP.getChannelByChannelIndex(TEST_CHANNEL);
+ Channel channel = mDP.getChannelByChannelIndex(TEST_CHANNEL_INDEX);
final float inputGain = channel.getInputGain();
assertEquals("inputGain is different", DEFAULT_INPUT_GAIN, inputGain, EPSILON);
@@ -145,7 +156,7 @@
try {
createDefaultEffect();
- DynamicsProcessing.Eq eq = mDP.getPreEqByChannelIndex(TEST_CHANNEL);
+ DynamicsProcessing.Eq eq = mDP.getPreEqByChannelIndex(TEST_CHANNEL_INDEX);
final boolean inUse = eq.isInUse();
assertEquals("inUse is different", DEFAULT_PREEQ_IN_USE, inUse);
@@ -165,7 +176,7 @@
try {
createDefaultEffect();
- DynamicsProcessing.Mbc mbc = mDP.getMbcByChannelIndex(TEST_CHANNEL);
+ DynamicsProcessing.Mbc mbc = mDP.getMbcByChannelIndex(TEST_CHANNEL_INDEX);
final boolean inUse = mbc.isInUse();
assertEquals("inUse is different", DEFAULT_MBC_IN_USE, inUse);
@@ -184,7 +195,7 @@
try {
createDefaultEffect();
- DynamicsProcessing.Eq eq = mDP.getPostEqByChannelIndex(TEST_CHANNEL);
+ DynamicsProcessing.Eq eq = mDP.getPostEqByChannelIndex(TEST_CHANNEL_INDEX);
boolean inUse = eq.isInUse();
assertEquals("inUse is different", DEFAULT_POSTEQ_IN_USE, inUse);
@@ -204,7 +215,7 @@
try {
createDefaultEffect();
- DynamicsProcessing.Limiter limiter = mDP.getLimiterByChannelIndex(TEST_CHANNEL);
+ DynamicsProcessing.Limiter limiter = mDP.getLimiterByChannelIndex(TEST_CHANNEL_INDEX);
final boolean inUse = limiter.isInUse();
assertEquals("inUse is different", DEFAULT_LIMITER_IN_USE, inUse);
@@ -214,10 +225,838 @@
}
//-----------------------------------------------------------------
- // 2 - run and change parameters
+ // 2 - config builder tests
//----------------------------------
- //TODO: runtime change of parameters.
+ public void test2_0ConfigBasic() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+ DynamicsProcessing.Config config = getBuilderWithValues().build();
+
+ assertEquals("getVariant is different", DEFAULT_VARIANT,
+ config.getVariant());
+ assertEquals("isPreEqInUse is different", DEFAULT_PREEQ_IN_USE,
+ config.isPreEqInUse());
+ assertEquals("getPreEqBandCount is different", DEFAULT_PREEQ_BAND_COUNT,
+ config.getPreEqBandCount());
+ assertEquals("isMbcInUse is different", DEFAULT_MBC_IN_USE,
+ config.isMbcInUse());
+ assertEquals("getMbcBandCount is different", DEFAULT_MBC_BAND_COUNT,
+ config.getMbcBandCount());
+ assertEquals("isPostEqInUse is different", DEFAULT_POSTEQ_IN_USE,
+ config.isPostEqInUse());
+ assertEquals("getPostEqBandCount is different", DEFAULT_POSTEQ_BAND_COUNT,
+ config.getPostEqBandCount());
+ assertEquals("isLimiterInUse is different", DEFAULT_LIMITER_IN_USE,
+ config.isLimiterInUse());
+ assertEquals("getPreferredFrameDuration is different", DEFAULT_FRAME_DURATION,
+ config.getPreferredFrameDuration());
+ }
+
+ public void test2_1ConfigChannel() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+ DynamicsProcessing.Config config = getBuilderWithValues(TEST_CHANNEL_COUNT).build();
+
+ //per channel
+ Channel channel = config.getChannelByChannelIndex(TEST_CHANNEL_INDEX);
+ //change some parameters
+ channel.setInputGain(TEST_GAIN1);
+
+ //get stages from channel
+ Eq preEq = channel.getPreEq();
+ EqBand preEqBand = preEq.getBand(TEST_BAND_INDEX);
+ preEqBand.setGain(TEST_GAIN1);
+ channel.setPreEqBand(TEST_BAND_INDEX, preEqBand);
+
+ Mbc mbc = channel.getMbc();
+ MbcBand mbcBand = mbc.getBand(TEST_BAND_INDEX);
+ mbcBand.setPreGain(TEST_GAIN1);
+ channel.setMbcBand(TEST_BAND_INDEX, mbcBand);
+
+ Eq postEq = channel.getPostEq();
+ EqBand postEqBand = postEq.getBand(TEST_BAND_INDEX);
+ postEqBand.setGain(TEST_GAIN1);
+ channel.setPostEqBand(TEST_BAND_INDEX, postEqBand);
+
+ Limiter limiter = channel.getLimiter();
+ limiter.setPostGain(TEST_GAIN1);
+ channel.setLimiter(limiter);
+
+ config.setAllChannelsTo(channel);
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ Channel channelTest = new Channel(config.getChannelByChannelIndex(i));
+ assertEquals("inputGain is different in channel " + i, TEST_GAIN1,
+ channelTest.getInputGain(), EPSILON);
+
+ EqBand preEqBandTest = new EqBand(channelTest.getPreEqBand(TEST_BAND_INDEX));
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, preEqBandTest.getGain(), EPSILON);
+
+ MbcBand mbcBandTest = new MbcBand(channelTest.getMbcBand(TEST_BAND_INDEX));
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, mbcBandTest.getPreGain(), EPSILON);
+
+ EqBand postEqBandTest = new EqBand(channelTest.getPostEqBand(TEST_BAND_INDEX));
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, postEqBandTest.getGain(), EPSILON);
+
+ Limiter limiterTest = new Limiter(channelTest.getLimiter());
+ assertEquals("limiter gain is different in channel " + i,
+ TEST_GAIN1, limiterTest.getPostGain(), EPSILON);
+
+ ///changes per channelIndex
+ channelTest.setInputGain(TEST_GAIN2);
+ preEqBandTest.setGain(TEST_GAIN2);
+ channelTest.setPreEqBand(TEST_BAND_INDEX, preEqBandTest);
+ mbcBandTest.setPreGain(TEST_GAIN2);
+ channelTest.setMbcBand(TEST_BAND_INDEX, mbcBandTest);
+ postEqBandTest.setGain(TEST_GAIN2);
+ channelTest.setPostEqBand(TEST_BAND_INDEX, postEqBandTest);
+ limiterTest.setPostGain(TEST_GAIN2);
+ channelTest.setLimiter(limiterTest);
+ config.setChannelTo(i, channelTest);
+
+ assertEquals("inputGain is different in channel " + i, TEST_GAIN2,
+ config.getInputGainByChannelIndex(i), EPSILON);
+
+ //get by module
+ Eq preEqTest = config.getPreEqByChannelIndex(i);
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, preEqTest.getBand(TEST_BAND_INDEX).getGain(), EPSILON);
+
+ Mbc mbcTest = config.getMbcByChannelIndex(i);
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, mbcTest.getBand(TEST_BAND_INDEX).getPreGain(), EPSILON);
+
+ Eq postEqTest = config.getPostEqByChannelIndex(i);
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, postEqTest.getBand(TEST_BAND_INDEX).getGain(), EPSILON);
+
+ limiterTest = config.getLimiterByChannelIndex(i);
+ assertEquals("limiter gain is different in channel " + i,
+ TEST_GAIN2, limiterTest.getPostGain(), EPSILON);
+ }
+ }
+
+ public void test2_2ConfigChannel_perStage() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ DynamicsProcessing.Config config = getBuilderWithValues(TEST_CHANNEL_COUNT).build();
+
+ //Per Stage
+ config.setInputGainAllChannelsTo(TEST_GAIN1);
+
+ Eq preEq = config.getPreEqByChannelIndex(TEST_CHANNEL_INDEX);
+ EqBand preEqBand = preEq.getBand(TEST_BAND_INDEX);
+ preEqBand.setGain(TEST_GAIN1);
+ preEq.setBand(TEST_BAND_INDEX, preEqBand);
+ config.setPreEqAllChannelsTo(preEq);
+
+ Mbc mbc = config.getMbcByChannelIndex(TEST_CHANNEL_INDEX);
+ MbcBand mbcBand = mbc.getBand(TEST_BAND_INDEX);
+ mbcBand.setPreGain(TEST_GAIN1);
+ mbc.setBand(TEST_BAND_INDEX, mbcBand);
+ config.setMbcAllChannelsTo(mbc);
+
+ Eq postEq = config.getPostEqByChannelIndex(TEST_CHANNEL_INDEX);
+ EqBand postEqBand = postEq.getBand(TEST_BAND_INDEX);
+ postEqBand.setGain(TEST_GAIN1);
+ postEq.setBand(TEST_BAND_INDEX, postEqBand);
+ config.setPostEqAllChannelsTo(postEq);
+
+ Limiter limiter = config.getLimiterByChannelIndex(TEST_CHANNEL_INDEX);
+ limiter.setPostGain(TEST_GAIN1);
+ config.setLimiterAllChannelsTo(limiter);
+
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ Channel channelTest = config.getChannelByChannelIndex(i);
+ assertEquals("inputGain is different in channel " + i, TEST_GAIN1,
+ channelTest.getInputGain(), EPSILON);
+
+ Eq preEqTest = new Eq(config.getPreEqByChannelIndex(i));
+ EqBand preEqBandTest = preEqTest.getBand(TEST_BAND_INDEX);
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, preEqBandTest.getGain(), EPSILON);
+
+ Mbc mbcTest = new Mbc(config.getMbcByChannelIndex(i));
+ MbcBand mbcBandTest = mbcTest.getBand(TEST_BAND_INDEX);
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, mbcBandTest.getPreGain(), EPSILON);
+
+ Eq postEqTest = new Eq(config.getPostEqByChannelIndex(i));
+ EqBand postEqBandTest = postEqTest.getBand(TEST_BAND_INDEX);
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, postEqBandTest.getGain(), EPSILON);
+
+ Limiter limiterTest = new Limiter(config.getLimiterByChannelIndex(i));
+ assertEquals("limiter gain is different in channel " + i,
+ TEST_GAIN1, limiterTest.getPostGain(), EPSILON);
+
+ //change by Stage
+ preEqBandTest.setGain(TEST_GAIN2);
+ preEqTest.setBand(TEST_BAND_INDEX, preEqBandTest);
+ config.setPreEqByChannelIndex(i, preEqTest);
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, config.getPreEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ mbcBandTest.setPreGain(TEST_GAIN2);
+ mbcTest.setBand(TEST_BAND_INDEX, mbcBandTest);
+ config.setMbcByChannelIndex(i, mbcTest);
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, config.getMbcBandByChannelIndex(i, TEST_BAND_INDEX).getPreGain(),
+ EPSILON);
+
+ postEqBandTest.setGain(TEST_GAIN2);
+ postEqTest.setBand(TEST_BAND_INDEX, postEqBandTest);
+ config.setPostEqByChannelIndex(i, postEqTest);
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, config.getPostEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ limiterTest.setPostGain(TEST_GAIN2);
+ config.setLimiterByChannelIndex(i, limiterTest);
+ assertEquals("limiter gain is different in channel " + i,
+ TEST_GAIN2, config.getLimiterByChannelIndex(i).getPostGain(), EPSILON);
+ }
+ }
+
+ public void test2_3ConfigChannel_perBand() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+ DynamicsProcessing.Config config = getBuilderWithValues(TEST_CHANNEL_COUNT).build();
+
+ //Per Band
+ EqBand preEqBand = config.getPreEqBandByChannelIndex(TEST_CHANNEL_INDEX, TEST_BAND_INDEX);
+ preEqBand.setGain(TEST_GAIN1);
+ config.setPreEqBandAllChannelsTo(TEST_BAND_INDEX, preEqBand);
+
+ MbcBand mbcBand = config.getMbcBandByChannelIndex(TEST_CHANNEL_INDEX, TEST_BAND_INDEX);
+ mbcBand.setPreGain(TEST_GAIN1);
+ config.setMbcBandAllChannelsTo(TEST_BAND_INDEX, mbcBand);
+
+ EqBand postEqBand = config.getPostEqBandByChannelIndex(TEST_CHANNEL_INDEX, TEST_BAND_INDEX);
+ postEqBand.setGain(TEST_GAIN1);
+ config.setPostEqBandAllChannelsTo(TEST_BAND_INDEX, postEqBand);
+
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+
+ EqBand preEqBandTest = new EqBand(config.getPreEqBandByChannelIndex(i,
+ TEST_BAND_INDEX));
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, preEqBandTest.getGain(), EPSILON);
+
+ MbcBand mbcBandTest = new MbcBand(config.getMbcBandByChannelIndex(i, TEST_BAND_INDEX));
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, mbcBandTest.getPreGain(), EPSILON);
+
+ EqBand postEqBandTest = new EqBand(config.getPostEqBandByChannelIndex(i,
+ TEST_BAND_INDEX));
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, postEqBandTest.getGain(), EPSILON);
+
+ //change per Band
+ preEqBandTest.setGain(TEST_GAIN2);
+ config.setPreEqBandByChannelIndex(i, TEST_BAND_INDEX, preEqBandTest);
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, config.getPreEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ mbcBandTest.setPreGain(TEST_GAIN2);
+ config.setMbcBandByChannelIndex(i, TEST_BAND_INDEX, mbcBandTest);
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, config.getMbcBandByChannelIndex(i, TEST_BAND_INDEX).getPreGain(),
+ EPSILON);
+
+ postEqBandTest.setGain(TEST_GAIN2);
+ config.setPostEqBandByChannelIndex(i, TEST_BAND_INDEX, postEqBandTest);
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, config.getPostEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+ }
+ }
+
+ public void test2_4Channel_perStage() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+ DynamicsProcessing.Config config = getBuilderWithValues(MIN_CHANNEL_COUNT).build();
+
+ Channel channel = new Channel(config.getChannelByChannelIndex(TEST_CHANNEL_INDEX));
+
+ channel.setInputGain(TEST_GAIN1);
+ assertEquals("channel gain is different", TEST_GAIN1, channel.getInputGain(), EPSILON);
+
+ //set by stage
+ Eq preEq = new Eq(channel.getPreEq());
+ EqBand preEqBand = new EqBand(preEq.getBand(TEST_BAND_INDEX));
+ preEqBand.setGain(TEST_GAIN1);
+ preEq.setBand(TEST_BAND_INDEX, preEqBand);
+ channel.setPreEq(preEq);
+ assertEquals("preEQBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, channel.getPreEq().getBand(TEST_BAND_INDEX).getGain(), EPSILON);
+ preEqBand.setGain(TEST_GAIN2);
+ preEq.setBand(TEST_BAND_INDEX, preEqBand);
+ channel.setPreEq(preEq);
+ assertEquals("preEQBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, channel.getPreEq().getBand(TEST_BAND_INDEX).getGain(), EPSILON);
+
+ Mbc mbc = new Mbc(channel.getMbc());
+ MbcBand mbcBand = new MbcBand(mbc.getBand(TEST_BAND_INDEX));
+ mbcBand.setPreGain(TEST_GAIN1);
+ mbc.setBand(TEST_BAND_INDEX, mbcBand);
+ channel.setMbc(mbc);
+ assertEquals("mbcBand preGain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, channel.getMbc().getBand(TEST_BAND_INDEX).getPreGain(), EPSILON);
+ mbcBand.setPreGain(TEST_GAIN2);
+ mbc.setBand(TEST_BAND_INDEX, mbcBand);
+ channel.setMbc(mbc);
+ assertEquals("mbcBand preGain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, channel.getMbc().getBand(TEST_BAND_INDEX).getPreGain(), EPSILON);
+
+ Eq postEq = new Eq(channel.getPostEq());
+ EqBand postEqBand = new EqBand(postEq.getBand(TEST_BAND_INDEX));
+ postEqBand.setGain(TEST_GAIN1);
+ postEq.setBand(TEST_BAND_INDEX, postEqBand);
+ channel.setPostEq(postEq);
+ assertEquals("postEqBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, channel.getPostEq().getBand(TEST_BAND_INDEX).getGain(), EPSILON);
+ postEqBand.setGain(TEST_GAIN2);
+ postEq.setBand(TEST_BAND_INDEX, postEqBand);
+ channel.setPostEq(postEq);
+ assertEquals("postEQBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, channel.getPostEq().getBand(TEST_BAND_INDEX).getGain(), EPSILON);
+
+ Limiter limiter = new Limiter(channel.getLimiter());
+ limiter.setPostGain(TEST_GAIN1);
+ channel.setLimiter(limiter);
+ assertEquals("limiter gain is different",
+ TEST_GAIN1, channel.getLimiter().getPostGain(), EPSILON);
+ limiter.setPostGain(TEST_GAIN2);
+ channel.setLimiter(limiter);
+ assertEquals("limiter gain is different",
+ TEST_GAIN2, channel.getLimiter().getPostGain(), EPSILON);
+
+ }
+
+ public void test2_5Channel_perBand() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+ DynamicsProcessing.Config config = getBuilderWithValues(MIN_CHANNEL_COUNT).build();
+
+ Channel channel = new Channel(config.getChannelByChannelIndex(TEST_CHANNEL_INDEX));
+
+ channel.setInputGain(TEST_GAIN1);
+ assertEquals("channel gain is different", TEST_GAIN1, channel.getInputGain(), EPSILON);
+
+ //set by band
+ EqBand preEqBand = new EqBand(channel.getPreEqBand(TEST_BAND_INDEX));
+ preEqBand.setGain(TEST_GAIN1);
+ channel.setPreEqBand(TEST_BAND_INDEX, preEqBand);
+ assertEquals("preEQBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, channel.getPreEqBand(TEST_BAND_INDEX).getGain(), EPSILON);
+ preEqBand.setGain(TEST_GAIN2);
+ channel.setPreEqBand(TEST_BAND_INDEX, preEqBand);
+ assertEquals("preEQBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, channel.getPreEqBand(TEST_BAND_INDEX).getGain(), EPSILON);
+
+ MbcBand mbcBand = new MbcBand(channel.getMbcBand(TEST_BAND_INDEX));
+ mbcBand.setPreGain(TEST_GAIN1);
+ channel.setMbcBand(TEST_BAND_INDEX, mbcBand);
+ assertEquals("mbcBand preGain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, channel.getMbcBand(TEST_BAND_INDEX).getPreGain(), EPSILON);
+ mbcBand.setPreGain(TEST_GAIN2);
+ channel.setMbcBand(TEST_BAND_INDEX, mbcBand);
+ assertEquals("mbcBand preGain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, channel.getMbcBand(TEST_BAND_INDEX).getPreGain(), EPSILON);
+
+ EqBand postEqBand = new EqBand(channel.getPostEqBand(TEST_BAND_INDEX));
+ postEqBand.setGain(TEST_GAIN1);
+ channel.setPostEqBand(TEST_BAND_INDEX, postEqBand);
+ assertEquals("postEqBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, channel.getPostEqBand(TEST_BAND_INDEX).getGain(), EPSILON);
+ postEqBand.setGain(TEST_GAIN2);
+ channel.setPostEqBand(TEST_BAND_INDEX, postEqBand);
+ assertEquals("postEqBand gain is different in band "+ TEST_BAND_INDEX,
+ TEST_GAIN2, channel.getPostEqBand(TEST_BAND_INDEX).getGain(), EPSILON);
+ }
+
+ public void test2_6Eq() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+ final boolean inUse = true;
+ final boolean enabled = true;
+ final int bandCount = 3;
+
+ Eq eq = new Eq(inUse, enabled, bandCount);
+ assertEquals("eq inUse is different", inUse, eq.isInUse());
+ assertEquals("eq enabled is different", enabled, eq.isEnabled());
+ assertEquals("eq bandCount is different", bandCount, eq.getBandCount());
+
+ //changes
+ eq.setEnabled(!enabled);
+ assertEquals("eq enabled is different", !enabled, eq.isEnabled());
+
+ //bands
+ for (int i = 0; i < bandCount; i++) {
+ final float frequency = (i + 1) * 100.3f;
+ final float gain = (i+1) * 10.1f;
+ EqBand eqBand = new EqBand(eq.getBand(i));
+
+ eqBand.setEnabled(enabled);
+ eqBand.setCutoffFrequency(frequency);
+ eqBand.setGain(gain);
+
+ eq.setBand(i, eqBand);
+
+ //compare
+ assertEquals("eq enabled is different in band " + i, enabled,
+ eq.getBand(i).isEnabled());
+ assertEquals("eq cutoffFrequency is different in band "+ i,
+ frequency, eq.getBand(i).getCutoffFrequency(), EPSILON);
+ assertEquals("eq eqBand gain is different in band "+ i,
+ gain, eq.getBand(i).getGain(), EPSILON);
+ }
+ }
+
+ public void test2_7Mbc() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final boolean inUse = true;
+ final boolean enabled = true;
+ final int bandCount = 3;
+
+ Mbc mbc = new Mbc(inUse, enabled, bandCount);
+ assertEquals("mbc inUse is different", inUse, mbc.isInUse());
+ assertEquals("mbc enabled is different", enabled, mbc.isEnabled());
+ assertEquals("mbc bandCount is different", bandCount, mbc.getBandCount());
+
+ //changes
+ mbc.setEnabled(!enabled);
+ assertEquals("enabled is different", !enabled, mbc.isEnabled());
+
+ //bands
+ for (int i = 0; i < bandCount; i++) {
+ int index = i+1;
+ final float frequency = index * 100.3f;
+ final float attackTime = index * 3.2f;
+ final float releaseTime = 2 * attackTime;
+ final float ratio = index * 1.2f;
+ final float threshold = index * (-12.8f);
+ final float kneeWidth = index * 0.3f;
+ final float noiseGateThreshold = index * (-20.1f);
+ final float expanderRatio = index * 1.1f;
+ final float preGain = index * 10.1f;
+ final float postGain = index * (-0.2f);
+ MbcBand mbcBand = new MbcBand(mbc.getBand(i));
+
+ mbcBand.setEnabled(enabled);
+ mbcBand.setCutoffFrequency(frequency);
+ mbcBand.setAttackTime(attackTime);
+ mbcBand.setReleaseTime(releaseTime);
+ mbcBand.setRatio(ratio);
+ mbcBand.setThreshold(threshold);
+ mbcBand.setKneeWidth(kneeWidth);
+ mbcBand.setNoiseGateThreshold(noiseGateThreshold);
+ mbcBand.setExpanderRatio(expanderRatio);
+ mbcBand.setPreGain(preGain);
+ mbcBand.setPostGain(postGain);
+
+ mbc.setBand(i, mbcBand);
+
+ //compare
+ assertEquals("mbc enabled is different", enabled, mbc.getBand(i).isEnabled());
+ assertEquals("mbc cutoffFrequency is different in band "+ i,
+ frequency, mbc.getBand(i).getCutoffFrequency(), EPSILON);
+ assertEquals("mbc attackTime is different in band "+ i,
+ attackTime, mbc.getBand(i).getAttackTime(), EPSILON);
+ assertEquals("mbc releaseTime is different in band "+ i,
+ releaseTime, mbc.getBand(i).getReleaseTime(), EPSILON);
+ assertEquals("mbc ratio is different in band "+ i,
+ ratio, mbc.getBand(i).getRatio(), EPSILON);
+ assertEquals("mbc threshold is different in band "+ i,
+ threshold, mbc.getBand(i).getThreshold(), EPSILON);
+ assertEquals("mbc kneeWidth is different in band "+ i,
+ kneeWidth, mbc.getBand(i).getKneeWidth(), EPSILON);
+ assertEquals("mbc noiseGateThreshold is different in band "+ i,
+ noiseGateThreshold, mbc.getBand(i).getNoiseGateThreshold(), EPSILON);
+ assertEquals("mbc expanderRatio is different in band "+ i,
+ expanderRatio, mbc.getBand(i).getExpanderRatio(), EPSILON);
+ assertEquals("mbc preGain is different in band "+ i,
+ preGain, mbc.getBand(i).getPreGain(), EPSILON);
+ assertEquals("mbc postGain is different in band "+ i,
+ postGain, mbc.getBand(i).getPostGain(), EPSILON);
+ }
+ }
+
+ public void test2_8Limiter() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final boolean inUse = true;
+ final boolean enabled = true;
+ final int linkGroup = 4;
+ final float attackTime = 3.2f;
+ final float releaseTime = 2 * attackTime;
+ final float ratio = 1.2f;
+ final float threshold = (-12.8f);
+ final float postGain = (-0.2f);
+
+ Limiter limiter = new Limiter(inUse, enabled, linkGroup, attackTime, releaseTime, ratio,
+ threshold, postGain);
+ assertEquals("limiter inUse is different", inUse, limiter.isInUse());
+ assertEquals("limiter enabled is different", enabled, limiter.isEnabled());
+ assertEquals("limiter linkGroup is different", linkGroup, limiter.getLinkGroup());
+
+ //defaults
+ assertEquals("limiter attackTime is different",
+ attackTime, limiter.getAttackTime(), EPSILON);
+ assertEquals("limiter releaseTime is different",
+ releaseTime, limiter.getReleaseTime(), EPSILON);
+ assertEquals("limiter ratio is different",
+ ratio, limiter.getRatio(), EPSILON);
+ assertEquals("limiter threshold is different",
+ threshold, limiter.getThreshold(), EPSILON);
+ assertEquals("limiter postGain is different",
+ postGain, limiter.getPostGain(), EPSILON);
+
+ //changes
+ final boolean newEnabled = !enabled;
+ final int newLinkGroup = 7;
+ final float newAttackTime = attackTime + 10;
+ final float newReleaseTime = releaseTime + 10;
+ final float newRatio = ratio + 2f;
+ final float newThreshold = threshold -20f;
+ final float newPostGain = postGain + 3f;
+
+ limiter.setEnabled(newEnabled);
+ limiter.setLinkGroup(newLinkGroup);
+ limiter.setAttackTime(newAttackTime);
+ limiter.setReleaseTime(newReleaseTime);
+ limiter.setRatio(newRatio);
+ limiter.setThreshold(newThreshold);
+ limiter.setPostGain(newPostGain);
+
+ assertEquals("limiter enabled is different", newEnabled, limiter.isEnabled());
+ assertEquals("limiter linkGroup is different", newLinkGroup, limiter.getLinkGroup());
+ assertEquals("limiter attackTime is different",
+ newAttackTime, limiter.getAttackTime(), EPSILON);
+ assertEquals("limiter releaseTime is different",
+ newReleaseTime, limiter.getReleaseTime(), EPSILON);
+ assertEquals("limiter ratio is different",
+ newRatio, limiter.getRatio(), EPSILON);
+ assertEquals("limiter threshold is different",
+ newThreshold, limiter.getThreshold(), EPSILON);
+ assertEquals("limiter postGain is different",
+ newPostGain, limiter.getPostGain(), EPSILON);
+ }
+
+ public void test2_9BandStage() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final boolean inUse = true;
+ final boolean enabled = true;
+ final int bandCount = 3;
+
+ BandStage bandStage = new BandStage(inUse, enabled, bandCount);
+ assertEquals("bandStage inUse is different", inUse, bandStage.isInUse());
+ assertEquals("bandStage enabled is different", enabled, bandStage.isEnabled());
+ assertEquals("bandStage bandCount is different", bandCount, bandStage.getBandCount());
+
+ //change
+ bandStage.setEnabled(!enabled);
+ assertEquals("bandStage enabled is different", !enabled, bandStage.isEnabled());
+ }
+
+ public void test2_10Stage() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final boolean inUse = true;
+ final boolean enabled = true;
+ final int bandCount = 3;
+
+ DynamicsProcessing.Stage stage = new DynamicsProcessing.Stage(inUse, enabled);
+ assertEquals("stage inUse is different", inUse, stage.isInUse());
+ assertEquals("stage enabled is different", enabled, stage.isEnabled());
+
+ //change
+ stage.setEnabled(!enabled);
+ assertEquals("stage enabled is different", !enabled, stage.isEnabled());
+ }
+
+ public void test2_11BandBase() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final boolean enabled = true;
+ final float frequency = 100.3f;
+
+ BandBase bandBase = new BandBase(enabled, frequency);
+
+ assertEquals("bandBase enabled is different", enabled, bandBase.isEnabled());
+ assertEquals("bandBase cutoffFrequency is different",
+ frequency, bandBase.getCutoffFrequency(), EPSILON);
+
+ //change
+ final float newFrequency = frequency + 10f;
+ bandBase.setEnabled(!enabled);
+ bandBase.setCutoffFrequency(newFrequency);
+ assertEquals("bandBase enabled is different", !enabled, bandBase.isEnabled());
+ assertEquals("bandBase cutoffFrequency is different",
+ newFrequency, bandBase.getCutoffFrequency(), EPSILON);
+ }
+ //-----------------------------------------------------------------
+ // 3 - Builder
+ //----------------------------------
+
+ public void test3_0Builder_stagesAllChannels() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ DynamicsProcessing.Config config = getBuilderWithValues(MIN_CHANNEL_COUNT).build();
+ DynamicsProcessing.Config.Builder builder = getBuilderWithValues(TEST_CHANNEL_COUNT);
+
+ //get Stages, apply all channels
+ Eq preEq = new Eq(config.getPreEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand preEqBand = new EqBand(preEq.getBand(TEST_BAND_INDEX));
+ preEqBand.setGain(TEST_GAIN1);
+ preEq.setBand(TEST_BAND_INDEX, preEqBand);
+ builder.setPreEqAllChannelsTo(preEq);
+
+ Mbc mbc = new Mbc(config.getMbcByChannelIndex(TEST_CHANNEL_INDEX));
+ MbcBand mbcBand = new MbcBand(mbc.getBand(TEST_BAND_INDEX));
+ mbcBand.setPreGain(TEST_GAIN1);
+ mbc.setBand(TEST_BAND_INDEX, mbcBand);
+ builder.setMbcAllChannelsTo(mbc);
+
+ Eq postEq = new Eq(config.getPostEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand postEqBand = new EqBand(postEq.getBand(TEST_BAND_INDEX));
+ postEqBand.setGain(TEST_GAIN1);
+ postEq.setBand(TEST_BAND_INDEX, postEqBand);
+ builder.setPostEqAllChannelsTo(postEq);
+
+ Limiter limiter = new Limiter(config.getLimiterByChannelIndex(TEST_CHANNEL_INDEX));
+ limiter.setPostGain(TEST_GAIN1);
+ builder.setLimiterAllChannelsTo(limiter);
+
+ //build and compare
+ DynamicsProcessing.Config newConfig = builder.build();
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, newConfig.getPreEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, newConfig.getMbcBandByChannelIndex(i, TEST_BAND_INDEX).getPreGain(),
+ EPSILON);
+
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, newConfig.getPostEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("limiter gain is different in channel " + i,
+ TEST_GAIN1, newConfig.getLimiterByChannelIndex(i).getPostGain(), EPSILON);
+ }
+ }
+
+ public void test3_1Builder_stagesByChannelIndex() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ DynamicsProcessing.Config config = getBuilderWithValues(MIN_CHANNEL_COUNT).build();
+ DynamicsProcessing.Config.Builder builder = getBuilderWithValues(TEST_CHANNEL_COUNT);
+
+ Eq preEq = new Eq(config.getPreEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand preEqBand = new EqBand(preEq.getBand(TEST_BAND_INDEX));
+
+ Mbc mbc = new Mbc(config.getMbcByChannelIndex(TEST_CHANNEL_INDEX));
+ MbcBand mbcBand = new MbcBand(mbc.getBand(TEST_BAND_INDEX));
+
+ Eq postEq = new Eq(config.getPostEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand postEqBand = new EqBand(postEq.getBand(TEST_BAND_INDEX));
+
+ Limiter limiter = new Limiter(config.getLimiterByChannelIndex(TEST_CHANNEL_INDEX));
+
+ //get Stages, apply per channel
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ float gain = i % 2 == 0 ? TEST_GAIN1 : TEST_GAIN2;
+
+ preEqBand.setGain(gain);
+ preEq.setBand(TEST_BAND_INDEX, preEqBand);
+ builder.setPreEqByChannelIndex(i, preEq);
+
+ mbcBand.setPreGain(gain);
+ mbc.setBand(TEST_BAND_INDEX, mbcBand);
+ builder.setMbcByChannelIndex(i, mbc);
+
+ postEqBand.setGain(gain);
+ postEq.setBand(TEST_BAND_INDEX, postEqBand);
+ builder.setPostEqByChannelIndex(i,postEq);
+
+ limiter.setPostGain(gain);
+ builder.setLimiterByChannelIndex(i, limiter);
+ }
+ //build and compare
+ DynamicsProcessing.Config newConfig = builder.build();
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ float expectedGain = i % 2 == 0 ? TEST_GAIN1 : TEST_GAIN2;
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ expectedGain,
+ newConfig.getPreEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ expectedGain,
+ newConfig.getMbcBandByChannelIndex(i, TEST_BAND_INDEX).getPreGain(),
+ EPSILON);
+
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ expectedGain,
+ newConfig.getPostEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("limiter gain is different in channel " + i,
+ expectedGain, newConfig.getLimiterByChannelIndex(i).getPostGain(), EPSILON);
+ }
+ }
+
+ public void test3_2Builder_setAllChannelsTo() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ DynamicsProcessing.Config config = getBuilderWithValues(MIN_CHANNEL_COUNT).build();
+ DynamicsProcessing.Config.Builder builder = getBuilderWithValues(TEST_CHANNEL_COUNT);
+
+ Channel channel = new Channel(config.getChannelByChannelIndex(TEST_CHANNEL_INDEX));
+
+ //get Stages, apply all channels
+ Eq preEq = new Eq(config.getPreEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand preEqBand = new EqBand(preEq.getBand(TEST_BAND_INDEX));
+ preEqBand.setGain(TEST_GAIN1);
+ preEq.setBand(TEST_BAND_INDEX, preEqBand);
+ channel.setPreEq(preEq);
+
+ Mbc mbc = new Mbc(config.getMbcByChannelIndex(TEST_CHANNEL_INDEX));
+ MbcBand mbcBand = new MbcBand(mbc.getBand(TEST_BAND_INDEX));
+ mbcBand.setPreGain(TEST_GAIN1);
+ mbc.setBand(TEST_BAND_INDEX, mbcBand);
+ channel.setMbc(mbc);
+
+ Eq postEq = new Eq(config.getPostEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand postEqBand = new EqBand(postEq.getBand(TEST_BAND_INDEX));
+ postEqBand.setGain(TEST_GAIN1);
+ postEq.setBand(TEST_BAND_INDEX, postEqBand);
+ channel.setPostEq(postEq);
+
+ Limiter limiter = new Limiter(config.getLimiterByChannelIndex(TEST_CHANNEL_INDEX));
+ limiter.setPostGain(TEST_GAIN1);
+ channel.setLimiter(limiter);
+
+ builder.setAllChannelsTo(channel);
+ //build and compare
+ DynamicsProcessing.Config newConfig = builder.build();
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, newConfig.getPreEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, newConfig.getMbcBandByChannelIndex(i, TEST_BAND_INDEX).getPreGain(),
+ EPSILON);
+
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ TEST_GAIN1, newConfig.getPostEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("limiter gain is different in channel " + i,
+ TEST_GAIN1, newConfig.getLimiterByChannelIndex(i).getPostGain(), EPSILON);
+ }
+ }
+
+ public void test3_3Builder_setChannelTo() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ DynamicsProcessing.Config config = getBuilderWithValues(MIN_CHANNEL_COUNT).build();
+ DynamicsProcessing.Config.Builder builder = getBuilderWithValues(TEST_CHANNEL_COUNT);
+
+ Channel channel = new Channel(config.getChannelByChannelIndex(TEST_CHANNEL_INDEX));
+
+ Eq preEq = new Eq(config.getPreEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand preEqBand = new EqBand(preEq.getBand(TEST_BAND_INDEX));
+
+ Mbc mbc = new Mbc(config.getMbcByChannelIndex(TEST_CHANNEL_INDEX));
+ MbcBand mbcBand = new MbcBand(mbc.getBand(TEST_BAND_INDEX));
+
+ Eq postEq = new Eq(config.getPostEqByChannelIndex(TEST_CHANNEL_INDEX));
+ EqBand postEqBand = new EqBand(postEq.getBand(TEST_BAND_INDEX));
+
+ Limiter limiter = new Limiter(config.getLimiterByChannelIndex(TEST_CHANNEL_INDEX));
+
+ //get Stages, apply per channel
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ float gain = i % 2 == 0 ? TEST_GAIN1 : TEST_GAIN2;
+
+ preEqBand.setGain(gain);
+ preEq.setBand(TEST_BAND_INDEX, preEqBand);
+ channel.setPreEq(preEq);
+
+ mbcBand.setPreGain(gain);
+ mbc.setBand(TEST_BAND_INDEX, mbcBand);
+ channel.setMbc(mbc);
+
+ postEqBand.setGain(gain);
+ postEq.setBand(TEST_BAND_INDEX, postEqBand);
+ channel.setPostEq(postEq);
+
+ limiter.setPostGain(gain);
+ channel.setLimiter(limiter);
+
+ builder.setChannelTo(i, channel);
+ }
+ //build and compare
+ DynamicsProcessing.Config newConfig = builder.build();
+ for (int i = 0; i < TEST_CHANNEL_COUNT; i++) {
+ float expectedGain = i % 2 == 0 ? TEST_GAIN1 : TEST_GAIN2;
+ assertEquals("preEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ expectedGain,
+ newConfig.getPreEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("mbcBand preGain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ expectedGain,
+ newConfig.getMbcBandByChannelIndex(i, TEST_BAND_INDEX).getPreGain(),
+ EPSILON);
+
+ assertEquals("postEQBand gain is different in channel " + i + " band "+ TEST_BAND_INDEX,
+ expectedGain,
+ newConfig.getPostEqBandByChannelIndex(i, TEST_BAND_INDEX).getGain(),
+ EPSILON);
+
+ assertEquals("limiter gain is different in channel " + i,
+ expectedGain, newConfig.getLimiterByChannelIndex(i).getPostGain(), EPSILON);
+ }
+ }
//-----------------------------------------------------------------
// private methods
//----------------------------------
@@ -260,11 +1099,11 @@
createDynamicsProcessingWithConfig(session, config);
}
- private DynamicsProcessing.Config.Builder getBuilder() {
+ private DynamicsProcessing.Config.Builder getBuilder(int channelCount) {
//simple config
DynamicsProcessing.Config.Builder builder = new DynamicsProcessing.Config.Builder(
DEFAULT_VARIANT /* variant */,
- MIN_CHANNEL_COUNT /* channels */,
+ channelCount/* channels */,
DEFAULT_PREEQ_IN_USE /*enable preEQ*/,
DEFAULT_PREEQ_BAND_COUNT /*preEq bands*/,
DEFAULT_MBC_IN_USE /*enable mbc*/,
@@ -276,13 +1115,18 @@
return builder;
}
- private DynamicsProcessing.Config.Builder getBuilderWithValues() {
+ private DynamicsProcessing.Config.Builder getBuilderWithValues(int channelCount) {
//simple config
- DynamicsProcessing.Config.Builder builder = getBuilder();
+ DynamicsProcessing.Config.Builder builder = getBuilder(channelCount);
//Set Defaults
builder.setPreferredFrameDuration(DEFAULT_FRAME_DURATION);
builder.setInputGainAllChannelsTo(DEFAULT_INPUT_GAIN);
return builder;
}
+
+ private DynamicsProcessing.Config.Builder getBuilderWithValues() {
+ return getBuilderWithValues(MIN_CHANNEL_COUNT);
+ }
+
}
\ No newline at end of file
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index 7427096..1e6f05e 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -723,8 +723,14 @@
mGLVersion / 10, mGLVersion % 10);
return false;
}
- if (desc.format == GL_RGBA16F && !HasGLExtension("GL_EXT_color_buffer_float")) {
- ALOGI("Test skipped: GL_RGBA16F requires GL_EXT_color_buffer_float");
+ if (desc.format == GL_RGB10_A2 && mGLVersion < 30) {
+ ALOGI("Test skipped: GL_RGB10_A2 requires GL ES 3.0, found %d.%d",
+ mGLVersion / 10, mGLVersion % 10);
+ return false;
+ }
+ if (desc.format == GL_RGBA16F &&
+ (!HasGLExtension("GL_EXT_color_buffer_float") && mGLVersion < 32)) {
+ ALOGI("Test skipped: GL_RGBA16F requires GL_EXT_color_buffer_float or GL ES 3.2");
return false;
}
// Nonzero stride indicates that desc.format should be interpreted as a GL format
diff --git a/tests/tests/os/AndroidTest.xml b/tests/tests/os/AndroidTest.xml
index b66c292..8f8d997 100644
--- a/tests/tests/os/AndroidTest.xml
+++ b/tests/tests/os/AndroidTest.xml
@@ -23,5 +23,11 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.os.cts" />
<option name="runtime-hint" value="3m15s" />
+ <!-- Do not disable hidden-api-checks for this test. This test includes
+ StrictModeTest which relies on hidden API checks being enabled in
+ order to function properly. Any APIs used by this test should be
+ added to the light grey list, or made @TestApi instead.
+ <option name="hidden-api-checks" value="false" />
+ -->
</test>
</configuration>
diff --git a/tests/tests/permission/src/android/permission/cts/ObserveAppUsagePermissionTest.java b/tests/tests/permission/src/android/permission/cts/ObserveAppUsagePermissionTest.java
new file mode 100644
index 0000000..720797e
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/ObserveAppUsagePermissionTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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.permission.cts;
+
+import static android.Manifest.permission.OBSERVE_APP_USAGE;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ObserveAppUsagePermissionTest {
+
+ private PackageManager mPackageManager;
+
+ @Before
+ public void setUp() {
+ mPackageManager = InstrumentationRegistry.getTargetContext().getPackageManager();
+ }
+
+ @Test
+ public void testNumberOfAppsWithPermission() {
+ final List<PackageInfo> packagesWithPerm = mPackageManager.getPackagesHoldingPermissions(
+ new String[]{OBSERVE_APP_USAGE}, 0);
+ assertTrue("At most one app can hold the permission " + OBSERVE_APP_USAGE
+ + ", but found more: " + packagesWithPerm, packagesWithPerm.size() <= 1);
+ }
+}
diff --git a/tests/tests/security/res/raw/cve_2017_13309_client.bks b/tests/tests/security/res/raw/cve_2017_13309_client.bks
new file mode 100644
index 0000000..6f450d3
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13309_client.bks
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_13309_server.bks b/tests/tests/security/res/raw/cve_2017_13309_server.bks
new file mode 100644
index 0000000..384c4be
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13309_server.bks
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_13309_trustedcert.bks b/tests/tests/security/res/raw/cve_2017_13309_trustedcert.bks
new file mode 100644
index 0000000..539d36e
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13309_trustedcert.bks
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/SSLConscryptPlainTextExposureTest.java b/tests/tests/security/src/android/security/cts/SSLConscryptPlainTextExposureTest.java
new file mode 100644
index 0000000..8f6477e
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/SSLConscryptPlainTextExposureTest.java
@@ -0,0 +1,866 @@
+/*
+ * Copyright (C) 2018 The AndroCid Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.platform.test.annotations.SecurityTest;
+import android.test.InstrumentationTestCase;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.Formatter;
+import java.util.Iterator;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Pattern;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManagerFactory;
+
+public class SSLConscryptPlainTextExposureTest extends InstrumentationTestCase {
+
+ private TestSSLServer mTestSSLServer;
+ private TestSSLConnection mTestSSLClient;
+ public static Context context;
+ public static String output = "";
+ private final String pattern = ".*PLAIN TEXT EXPOSED.*";
+
+ public void test_android_CVE_2017_13309() {
+
+ context = getInstrumentation().getContext();
+ mTestSSLServer = new TestSSLServer();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mTestSSLClient = new TestSSLConnection();
+ mTestSSLClient.StartConnect();
+ assertFalse("Pattern found",
+ Pattern.compile(pattern,
+ Pattern.DOTALL).matcher(output).matches());
+ }
+
+ public static InputStream getResource(final int resource){
+ return SSLConscryptPlainTextExposureTest.context.getResources().openRawResource(resource);
+ }
+
+ public static void setOutput(String data){
+ SSLConscryptPlainTextExposureTest.output = data;
+ }
+}
+
+
+class TestSSLConnection {
+
+ public SSLContext sslc;
+
+ public SocketChannel socketChannel;
+ public SSLEngine clientEngine;
+ public String remoteAddress = "127.0.0.1";
+ public int port = 9000;
+ public ByteBuffer[] dataOutAppBuffers = new ByteBuffer[3];
+ public ByteBuffer dataOutNetBuffer;
+ public ByteBuffer hsInAppBuffer, hsInNetBuffer, hsOutAppBuffer, hsOutNetBuffer;
+ public boolean isHandshaked = false;
+ public ExecutorService executor = Executors.newSingleThreadExecutor();
+ public InputStream clientKey = null;
+ public InputStream trustedCert = null;
+
+ public void StartConnect() {
+ KeyStore ks = null;
+
+ clientKey = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_client);
+ trustedCert = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_trustedcert);
+
+ try {
+ ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ }
+ KeyStore ts = null;
+ try {
+ ts = KeyStore.getInstance(KeyStore.getDefaultType());
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ ks.load(clientKey, "pocclient".toCharArray());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ ts.load(trustedCert, "trusted".toCharArray());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ KeyManagerFactory kmf = null;
+ try {
+ kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ kmf.init(ks, "keypass".toCharArray());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ TrustManagerFactory tmf = null;
+ try {
+ tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ try {
+ tmf.init(ts);
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ }
+
+ SSLContext sslCtx = null;
+ try {
+ sslCtx = SSLContext.getInstance("TLSv1.2");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ } catch (KeyManagementException e) {
+ e.printStackTrace();
+ }
+
+ sslc = sslCtx;
+
+ clientEngine = sslc.createSSLEngine(remoteAddress, port);
+ clientEngine.setUseClientMode(true);
+ SSLSession session = clientEngine.getSession();
+
+ hsOutAppBuffer = ByteBuffer.allocate(4096);
+ hsOutNetBuffer = ByteBuffer.allocate(session.getPacketBufferSize());
+ hsInAppBuffer = ByteBuffer.allocate(4096);
+ hsInNetBuffer = ByteBuffer.allocate(session.getPacketBufferSize());
+ dataOutNetBuffer = ByteBuffer.allocate(session.getPacketBufferSize());
+
+ try {
+ socketChannel = SocketChannel.open();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ socketChannel.configureBlocking(false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ socketChannel.connect(new InetSocketAddress(remoteAddress, port));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ while(!socketChannel.finishConnect()) {
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ clientEngine.beginHandshake();
+ } catch (SSLException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ isHandshaked = doHandshake(socketChannel, clientEngine);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if(isHandshaked) {
+ dataOutAppBuffers[0] = ByteBuffer.wrap("PLAIN TEXT EXPOSED".getBytes());
+ dataOutAppBuffers[1] = ByteBuffer.wrap("PLAIN TEXT EXPOSED".getBytes());
+ dataOutAppBuffers[2] = ByteBuffer.wrap("PLAIN TEXT EXPOSED".getBytes());
+
+ while(dataOutAppBuffers[0].hasRemaining() || dataOutAppBuffers[1].hasRemaining() || dataOutAppBuffers[2].hasRemaining()) {
+ dataOutNetBuffer.clear();
+ SSLEngineResult result = null;
+ try {
+ result = clientEngine.wrap(dataOutAppBuffers, 0, 3, dataOutNetBuffer);
+ } catch (SSLException e) {
+ e.printStackTrace();
+ }
+ switch(result.getStatus()) {
+ case OK:
+ dataOutNetBuffer.flip();
+ String outbuff = new String("");
+ Formatter formatter = new Formatter();
+ for(int i = 0; i < dataOutNetBuffer.limit(); i++) {
+ outbuff += formatter.format("%02x ", dataOutNetBuffer.get(i)).toString();
+ }
+ String output = new String(dataOutNetBuffer.array());
+ SSLConscryptPlainTextExposureTest.setOutput(output);
+ break;
+ case BUFFER_OVERFLOW:
+ dataOutNetBuffer = enlargePacketBuffer(clientEngine, dataOutNetBuffer);
+ break;
+ case BUFFER_UNDERFLOW:
+ try {
+ throw new SSLException("Buffer underflow in sending data");
+ } catch (SSLException e) {
+ e.printStackTrace();
+ }
+ case CLOSED:
+ try {
+ closeConnection(socketChannel, clientEngine);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return;
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
+ }
+ }
+ }
+
+ try {
+ clientKey.close();
+ } catch (IOException e){
+ e.printStackTrace();
+ }
+
+ try{
+ trustedCert.close();
+ } catch (IOException e){
+ e.printStackTrace();
+ }
+
+ try {
+ shutdown();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void shutdown() throws IOException {
+ closeConnection(socketChannel, clientEngine);
+ executor.shutdown();
+ }
+
+ public void closeConnection(SocketChannel socketChannel, SSLEngine engine) throws IOException {
+ engine.closeOutbound();
+ doHandshake(socketChannel, engine);
+ socketChannel.close();
+ }
+
+ public boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) throws IOException {
+ SSLEngineResult result;
+ SSLEngineResult.HandshakeStatus handshakeStatus;
+ int appBufferSize = engine.getSession().getApplicationBufferSize();
+
+ ByteBuffer srcAppData = ByteBuffer.allocate(appBufferSize);
+ ByteBuffer dstAppData = ByteBuffer.allocate(appBufferSize);
+
+ srcAppData.clear();
+ dstAppData.clear();
+
+ handshakeStatus = engine.getHandshakeStatus();
+ while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED
+ && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+ switch(handshakeStatus) {
+ case NEED_UNWRAP:
+ if(socketChannel.read(hsInNetBuffer) < 0) {
+ if(engine.isInboundDone() && engine.isOutboundDone()) {
+ return false;
+ }
+ try {
+ engine.closeInbound();
+ } catch (SSLException e) {
+ Log.e("poc-test","Forced to close inbound. No proper SSL/TLS close notification message from peer");
+ }
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ hsInNetBuffer.flip();
+ try {
+ result = engine.unwrap(hsInNetBuffer, hsInAppBuffer);
+ hsInNetBuffer.compact();
+ handshakeStatus = result.getHandshakeStatus();
+ } catch (SSLException sslException) {
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ switch(result.getStatus()) {
+ case OK:
+ break;
+ case BUFFER_OVERFLOW:
+ hsInAppBuffer = enlargeApplicationBuffer(engine, hsInAppBuffer);
+ break;
+ case BUFFER_UNDERFLOW:
+ hsInNetBuffer = handleBufferUnderflow(engine, hsInNetBuffer);
+ break;
+ case CLOSED:
+ if (engine.isOutboundDone()) {
+ return false;
+ } else {
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
+ }
+ case NEED_WRAP:
+ hsOutNetBuffer.clear();
+ try {
+ result = engine.wrap(hsOutAppBuffer, hsOutNetBuffer);
+ handshakeStatus = result.getHandshakeStatus();
+ } catch (SSLException sslException) {
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ switch(result.getStatus()) {
+ case OK:
+ hsOutNetBuffer.flip();
+ while(hsOutNetBuffer.hasRemaining()) {
+ socketChannel.write(hsOutNetBuffer);
+ }
+ break;
+ case BUFFER_OVERFLOW:
+ hsOutNetBuffer = enlargePacketBuffer(engine, hsOutNetBuffer);
+ break;
+ case BUFFER_UNDERFLOW:
+ throw new SSLException("Buffer underflow in handshake and wrap");
+ case CLOSED:
+ try {
+ hsOutNetBuffer.flip();
+ while(hsOutNetBuffer.hasRemaining()) {
+ socketChannel.write(hsOutNetBuffer);
+ }
+ hsInNetBuffer.clear();
+ } catch (Exception e) {
+ handshakeStatus = engine.getHandshakeStatus();
+ }
+ break;
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
+ }
+ break;
+ case NEED_TASK:
+ Runnable task;
+ while((task = engine.getDelegatedTask()) != null) {
+ executor.execute(task);
+ }
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ case FINISHED:
+ break;
+ case NOT_HANDSHAKING:
+ break;
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + handshakeStatus);
+ }
+ }
+ return true;
+ }
+
+ public ByteBuffer enlargePacketBuffer(SSLEngine engine, ByteBuffer buffer) {
+ return enlargeBuffer(buffer, engine.getSession().getPacketBufferSize());
+ }
+
+ public ByteBuffer enlargeApplicationBuffer(SSLEngine engine, ByteBuffer buffer) {
+ return enlargeBuffer(buffer, engine.getSession().getApplicationBufferSize());
+ }
+
+ public ByteBuffer enlargeBuffer(ByteBuffer buffer, int bufferSize) {
+ if(bufferSize > buffer.capacity()) {
+ buffer = ByteBuffer.allocate(bufferSize);
+ }
+ else {
+ buffer = ByteBuffer.allocate(buffer.capacity() * 2);
+ }
+ return buffer;
+ }
+ public ByteBuffer handleBufferUnderflow(SSLEngine engine, ByteBuffer buffer) {
+ if(engine.getSession().getPacketBufferSize() < buffer.limit()) {
+ return buffer;
+ }
+ else {
+ ByteBuffer replaceBuffer = enlargePacketBuffer(engine, buffer);
+ buffer.flip();
+ replaceBuffer.put(buffer);
+ return replaceBuffer;
+ }
+ }
+}
+
+class TestSSLServer {
+
+ public ServerRunnable serverRunnable;
+ Thread server;
+
+ public TestSSLServer() {
+ serverRunnable = new ServerRunnable();
+ server = new Thread(serverRunnable);
+ server.start();
+
+ try{
+ Thread.sleep(1000);
+ }catch(InterruptedException e){
+ e.printStackTrace();
+ }
+ }
+
+ protected void onCancelled(String result) {
+ serverRunnable.stop();
+ }
+}
+
+class ServerRunnable implements Runnable {
+
+ SSLServer server;
+ InputStream serverKey = null;
+ InputStream trustedCert = null;
+
+ public void run() {
+ try {
+ server = new SSLServer();
+ server.runServer();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop() {
+ server.stopServer();
+ }
+}
+
+class SSLServer {
+ public SSLContext serverContext;
+
+ public ByteBuffer hsInAppBuffer, hsInNetBuffer, hsOutAppBuffer, hsOutNetBuffer;
+ public ByteBuffer dataInAppBuffer, dataInNetBuffer;
+
+ final String hostAddress = "127.0.0.1";
+ public int port = 9000;
+ public boolean bActive = false;
+
+ public Selector selector;
+ InputStream serverKey = null;
+ InputStream trustedCert = null;
+ public ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ public void stopServer() {
+ bActive = false;
+ executor.shutdown();
+ selector.wakeup();
+ }
+
+ public void runServer() {
+ KeyStore ks = null;
+
+ serverKey = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_server);
+ trustedCert = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_trustedcert);
+
+ try {
+ ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ }
+ KeyStore ts = null;
+ try {
+ ts = KeyStore.getInstance(KeyStore.getDefaultType());
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ ks.load(serverKey, "pocserver".toCharArray());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ ts.load(trustedCert, "trusted".toCharArray());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ KeyManagerFactory kmf = null;
+ try {
+ kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ try {
+ kmf.init(ks, "keypass".toCharArray());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ TrustManagerFactory tmf = null;
+ try {
+ tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ try {
+ tmf.init(ts);
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ }
+
+ SSLContext sslCtx = null;
+ try {
+ sslCtx = SSLContext.getInstance("TLSv1.2");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
+ } catch (KeyManagementException e) {
+ e.printStackTrace();
+ }
+
+ serverContext = sslCtx;
+
+ SSLSession dummySession = serverContext.createSSLEngine().getSession();
+
+ hsInAppBuffer = ByteBuffer.allocate(4096);
+ hsInNetBuffer = ByteBuffer.allocate(dummySession.getPacketBufferSize());
+ hsOutAppBuffer = ByteBuffer.allocate(4096);
+ hsOutNetBuffer = ByteBuffer.allocate(dummySession.getPacketBufferSize());
+ dataInAppBuffer = ByteBuffer.allocate(4096);
+ dataInNetBuffer = ByteBuffer.allocate(dummySession.getPacketBufferSize());
+ dummySession.invalidate();
+
+ try {
+ selector = SelectorProvider.provider().openSelector();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ ServerSocketChannel serverSocketChannel = null;
+ try {
+ serverSocketChannel = ServerSocketChannel.open();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ serverSocketChannel.configureBlocking(false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ serverSocketChannel.socket().bind(new InetSocketAddress(hostAddress, port));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
+ } catch (ClosedChannelException e) {
+ e.printStackTrace();
+ }
+
+ bActive = true;
+
+ while(bActive) {
+ try {
+ selector.select();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
+ while (selectedKeys.hasNext()) {
+ SelectionKey key = selectedKeys.next();
+ selectedKeys.remove();
+ if (!key.isValid()) {
+ continue;
+ }
+ if (key.isAcceptable()) {
+ try {
+ accept(key);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else if (key.isReadable()) {
+ try {
+ read((SocketChannel) key.channel(), (SSLEngine) key.attachment());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ public void accept(SelectionKey key) throws Exception{
+ SocketChannel socketChannel = ((ServerSocketChannel)key.channel()).accept();
+ socketChannel.configureBlocking(false);
+
+ SSLEngine engine = serverContext.createSSLEngine();
+ engine.setUseClientMode(false);
+ engine.beginHandshake();
+
+ socketChannel.register(selector, SelectionKey.OP_READ, engine);
+
+ if(doHandshake(socketChannel, engine)) {
+ socketChannel.register(selector, SelectionKey.OP_READ, engine);
+ }
+ else {
+ socketChannel.close();
+ }
+ }
+
+ public boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) throws IOException {
+ SSLEngineResult result = null;
+ SSLEngineResult.HandshakeStatus handshakeStatus;
+ int appBufferSize = engine.getSession().getApplicationBufferSize();
+
+ ByteBuffer srcAppData = ByteBuffer.allocate(appBufferSize);
+ ByteBuffer dstAppData = ByteBuffer.allocate(appBufferSize);
+
+ srcAppData.clear();
+ dstAppData.clear();
+
+ handshakeStatus = engine.getHandshakeStatus();
+ while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED
+ && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+
+ switch(handshakeStatus) {
+ case NEED_UNWRAP:
+ if(socketChannel.read(hsInNetBuffer) < 0) {
+ if(engine.isInboundDone() && engine.isOutboundDone()) {
+ return false;
+ }
+ try {
+ engine.closeInbound();
+ } catch (SSLException e) {
+ Log.e("server-poc-test","Forced to close inbound. No proper SSL/TLS close notification message from peer");
+ }
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ hsInNetBuffer.flip();
+ try {
+ result = engine.unwrap(hsInNetBuffer, hsInAppBuffer);
+ hsInNetBuffer.compact();
+ handshakeStatus = result.getHandshakeStatus();
+ } catch (SSLException sslException) {
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ switch(result.getStatus()) {
+ case OK:
+ break;
+ case BUFFER_OVERFLOW:
+ hsInAppBuffer = enlargeApplicationBuffer(engine, hsInAppBuffer);
+ break;
+ case BUFFER_UNDERFLOW:
+ hsInNetBuffer = handleBufferUnderflow(engine, hsInNetBuffer);
+ break;
+ case CLOSED:
+ if (engine.isOutboundDone()) {
+ return false;
+ } else {
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
+ }
+ case NEED_WRAP:
+ hsOutNetBuffer.clear();
+ try {
+ result = engine.wrap(hsOutAppBuffer, hsOutNetBuffer);
+ handshakeStatus = result.getHandshakeStatus();
+ } catch (SSLException sslException) {
+ engine.closeOutbound();
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ }
+ switch(result.getStatus()) {
+ case OK:
+ hsOutNetBuffer.flip();
+ while(hsOutNetBuffer.hasRemaining()) {
+ socketChannel.write(hsOutNetBuffer);
+ }
+ break;
+ case BUFFER_OVERFLOW:
+ hsOutNetBuffer = enlargePacketBuffer(engine, hsOutNetBuffer);
+ break;
+ case BUFFER_UNDERFLOW:
+ throw new SSLException("Buffer underflow in handshake and wrap");
+ case CLOSED:
+ try {
+ hsOutNetBuffer.flip();
+ while(hsOutNetBuffer.hasRemaining()) {
+ socketChannel.write(hsOutNetBuffer);
+ }
+ hsInNetBuffer.clear();
+ } catch (Exception e) {
+ handshakeStatus = engine.getHandshakeStatus();
+ }
+ break;
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
+ }
+ break;
+ case NEED_TASK:
+ Runnable task;
+ while((task = engine.getDelegatedTask()) != null) {
+ executor.execute(task);
+ }
+ handshakeStatus = engine.getHandshakeStatus();
+ break;
+ case FINISHED:
+ break;
+ case NOT_HANDSHAKING:
+ break;
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + handshakeStatus);
+ }
+ }
+ return true;
+ }
+
+ public ByteBuffer enlargePacketBuffer(SSLEngine engine, ByteBuffer buffer) {
+ return enlargeBuffer(buffer, engine.getSession().getPacketBufferSize());
+ }
+
+ public ByteBuffer enlargeApplicationBuffer(SSLEngine engine, ByteBuffer buffer) {
+ return enlargeBuffer(buffer, engine.getSession().getApplicationBufferSize());
+ }
+
+ public ByteBuffer enlargeBuffer(ByteBuffer buffer, int bufferSize) {
+ if(bufferSize > buffer.capacity()) {
+ buffer = ByteBuffer.allocate(bufferSize);
+ }
+ else {
+ buffer = ByteBuffer.allocate(buffer.capacity() * 2);
+ }
+ return buffer;
+ }
+ public ByteBuffer handleBufferUnderflow(SSLEngine engine, ByteBuffer buffer) {
+ if(engine.getSession().getPacketBufferSize() < buffer.limit()) {
+ return buffer;
+ }
+ else {
+ ByteBuffer replaceBuffer = enlargePacketBuffer(engine, buffer);
+ buffer.flip();
+ replaceBuffer.put(buffer);
+ return replaceBuffer;
+ }
+ }
+
+ public void read(SocketChannel socketChannel, SSLEngine engine) throws IOException {
+ dataInNetBuffer.clear();
+ int bytesRead = socketChannel.read(dataInNetBuffer);
+ if(bytesRead > 0) {
+ dataInNetBuffer.flip();
+ while(dataInNetBuffer.hasRemaining()) {
+ dataInAppBuffer.clear();
+ SSLEngineResult result = engine.unwrap(dataInNetBuffer, dataInAppBuffer);
+ switch(result.getStatus()) {
+ case OK:
+ dataInAppBuffer.flip();
+ break;
+ case BUFFER_OVERFLOW:
+ dataInAppBuffer = enlargeApplicationBuffer(engine, dataInAppBuffer);
+ break;
+ case BUFFER_UNDERFLOW:
+ dataInNetBuffer = handleBufferUnderflow(engine, dataInNetBuffer);
+ break;
+ case CLOSED:
+ closeConnection(socketChannel, engine);
+ return;
+ default:
+ throw new IllegalStateException("invalid SSL status: " + result.getStatus());
+ }
+ }
+ }
+ else if(bytesRead < 0) {
+ handleEndOfStream(socketChannel, engine);
+ }
+ }
+
+ public void handleEndOfStream(SocketChannel socketChannel, SSLEngine engine) throws IOException {
+ try {
+ engine.closeInbound();
+ }
+ catch (Exception e) {
+ Log.e("server-poc-test", "Close inbound forced");
+ }
+ closeConnection(socketChannel, engine);
+ }
+
+ public void closeConnection(SocketChannel socketChannel, SSLEngine engine) throws IOException {
+ try{
+ serverKey.close();
+ } catch (IOException e){
+ e.printStackTrace();
+ }
+
+ try {
+ trustedCert.close();
+ } catch (IOException e){
+ e.printStackTrace();
+ }
+
+ engine.closeOutbound();
+ doHandshake(socketChannel, engine);
+ socketChannel.close();
+ }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
index 0b708d4..ecd8dfc 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
@@ -35,6 +35,6 @@
.addLayout(R.layout.frame_layout,
view -> view.setBackgroundResource(R.drawable.dashed_oval))
.runWithVerifier(new GoldenImageVerifier(getActivity(),
- R.drawable.golden_dashed_oval, new MSSIMComparer(0.99)));
+ R.drawable.golden_dashed_oval, new MSSIMComparer(0.90)));
}
}
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index f27c81d..3607e57 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -35,10 +35,13 @@
* Neverallow Rules SELinux tests.
*/
public class SELinuxNeverallowRulesTest extends DeviceTestCase implements IBuildReceiver, IDeviceTest {
+ private static final int P_SEPOLICY_VERSION = 28;
private File sepolicyAnalyze;
private File devicePolicyFile;
+ private File deviceSystemPolicyFile;
private IBuildInfo mBuild;
+ private int mVendorSepolicyVersion = -1;
/**
* A reference to the device under test.
@@ -69,6 +72,14 @@
sepolicyAnalyze.setExecutable(true);
devicePolicyFile = android.security.cts.SELinuxHostTest.getDevicePolicyFile(mDevice);
+ deviceSystemPolicyFile =
+ android.security.cts.SELinuxHostTest.getDeviceSystemPolicyFile(mDevice);
+
+ // Caching this variable to save time.
+ if (mVendorSepolicyVersion == -1) {
+ mVendorSepolicyVersion =
+ android.security.cts.SELinuxHostTest.getVendorSepolicyVersion(mDevice);
+ }
}
private boolean isFullTrebleDevice() throws Exception {
@@ -100,9 +111,15 @@
return;
}
+ // If vendor sepolicy version is behind platform's, only test against platform policy.
+ File policyFile =
+ (mVendorSepolicyVersion < P_SEPOLICY_VERSION) ?
+ deviceSystemPolicyFile :
+ devicePolicyFile;
+
/* run sepolicy-analyze neverallow check on policy file using given neverallow rules */
ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
- devicePolicyFile.getAbsolutePath(), "neverallow", "-w", "-n",
+ policyFile.getAbsolutePath(), "neverallow", "-w", "-n",
neverallowRule);
pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
pb.redirectErrorStream(true);