Merge "Remove unimplemented and unused service declaration"
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
index a5ceaba..10e100d 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
@@ -51,11 +51,11 @@
tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb0 = its.image.compute_image_means(tile)
- # Raw shots are 1/2 x 1/2 smaller after conversion to RGB, so scale the
- # tile appropriately.
+ # Raw shots are 1/2 x 1/2 smaller after conversion to RGB, but tile
+ # cropping is relative.
img = its.image.convert_capture_to_rgb_image(cap_raw, props=props)
its.image.write_image(img, "%s_raw.jpg" % (NAME), True)
- tile = its.image.get_image_patch(img, 0.475, 0.475, 0.05, 0.05)
+ tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb1 = its.image.compute_image_means(tile)
rms_diff = math.sqrt(
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
index f281089..be5f701 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
@@ -51,11 +51,11 @@
tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb0 = its.image.compute_image_means(tile)
- # Raw shots are 1/2 x 1/2 smaller after conversion to RGB, so scale the
- # tile appropriately.
+ # Raw shots are 1/2 x 1/2 smaller after conversion to RGB, but tile
+ # cropping is relative.
img = its.image.convert_capture_to_rgb_image(cap_raw, props=props)
its.image.write_image(img, "%s_raw.jpg" % (NAME), True)
- tile = its.image.get_image_patch(img, 0.475, 0.475, 0.05, 0.05)
+ tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb1 = its.image.compute_image_means(tile)
rms_diff = math.sqrt(
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
index 5b6051a..8070785 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
@@ -51,11 +51,11 @@
tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb0 = its.image.compute_image_means(tile)
- # Raw shots are 1/2 x 1/2 smaller after conversion to RGB, so scale the
- # tile appropriately.
+ # Raw shots are 1/2 x 1/2 smaller after conversion to RGB, but tile
+ # cropping is relative.
img = its.image.convert_capture_to_rgb_image(cap_raw, props=props)
its.image.write_image(img, "%s_raw.jpg" % (NAME), True)
- tile = its.image.get_image_patch(img, 0.475, 0.475, 0.05, 0.05)
+ tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb1 = its.image.compute_image_means(tile)
rms_diff = math.sqrt(
diff --git a/apps/CameraITS/tests/scene2/test_faces.py b/apps/CameraITS/tests/scene2/test_faces.py
index 8a3a403..4e30fc1 100644
--- a/apps/CameraITS/tests/scene2/test_faces.py
+++ b/apps/CameraITS/tests/scene2/test_faces.py
@@ -13,6 +13,7 @@
# limitations under the License.
import its.image
+import its.caps
import its.device
import its.objects
import os.path
@@ -32,13 +33,14 @@
fd_modes = props['android.statistics.info.availableFaceDetectModes']
a = props['android.sensor.info.activeArraySize']
aw, ah = a['right'] - a['left'], a['bottom'] - a['top']
- gain, exp, _, _, focus = cam.do_3a(get_results=True)
- print 'iso = %d' % gain
- print 'exp = %.2fms' % (exp*1.0E-6)
- if focus == 0.0:
- print 'fd = infinity'
- else:
- print 'fd = %.2fcm' % (1.0E2/focus)
+ if its.caps.read_3a(props):
+ gain, exp, _, _, focus = cam.do_3a(get_results=True)
+ print 'iso = %d' % gain
+ print 'exp = %.2fms' % (exp*1.0E-6)
+ if focus == 0.0:
+ print 'fd = infinity'
+ else:
+ print 'fd = %.2fcm' % (1.0E2/focus)
for fd_mode in fd_modes:
assert(FD_MODE_OFF <= fd_mode <= FD_MODE_FULL)
req = its.objects.auto_capture_request()
diff --git a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
index 1307680..f8a97e4 100644
--- a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
+++ b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
@@ -52,16 +52,16 @@
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
- its.caps.skip_unless(its.caps.read_3a(props))
- # Converge 3A and get the estimates.
- sens, exp, gains, xform, focus = cam.do_3a(get_results=True,
- do_af=False,
- lock_ae=True,
- lock_awb=True)
- print "AE sensitivity %d, exposure %dms" % (sens, exp / 1000000.0)
- print "AWB gains", gains
- print "AWB transform", xform
- print "AF distance", focus
+ if its.caps.read_3a(props):
+ # Converge 3A and get the estimates.
+ sens, exp, gains, xform, focus = cam.do_3a(get_results=True,
+ do_af=False,
+ lock_ae=True,
+ lock_awb=True)
+ print "AE sensitivity %d, exposure %dms" % (sens, exp / 1000000.0)
+ print "AWB gains", gains
+ print "AWB transform", xform
+ print "AF distance", focus
req = its.objects.auto_capture_request()
img_size = its.objects.get_available_output_sizes("yuv", props)
w = img_size[0][0]
diff --git a/common/host-side/tradefed/res/report/compatibility_failures.xsl b/common/host-side/tradefed/res/report/compatibility_failures.xsl
new file mode 100644
index 0000000..be65b91
--- /dev/null
+++ b/common/host-side/tradefed/res/report/compatibility_failures.xsl
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
+
+ <xsl:template match="/">
+
+ <html>
+ <head>
+ <title>Test Report</title>
+ <style type="text/css">
+ @import "compatibility_result.css";
+ </style>
+ </head>
+ <body>
+ <div>
+ <table class="title">
+ <tr>
+ <td align="left"><img src="logo.png"/></td>
+ </tr>
+ </table>
+ </div>
+
+ <div>
+ <table class="summary">
+ <tr>
+ <th colspan="2">Summary</th>
+ </tr>
+ <tr>
+ <td class="rowtitle">Suite / Plan</td>
+ <td>
+ <xsl:value-of select="Result/@suite_name"/> / <xsl:value-of select="Result/@suite_plan"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Suite / Build</td>
+ <td>
+ <xsl:value-of select="Result/@suite_version"/> / <xsl:value-of select="Result/@suite_build_number"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Host Info</td>
+ <td>
+ Result/@start
+ <xsl:value-of select="Result/@host_name"/>
+ (<xsl:value-of select="Result/@os_name"/> - <xsl:value-of select="Result/@os_version"/>)
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Start time / End Time</td>
+ <td>
+ <xsl:value-of select="Result/@start_display"/> /
+ <xsl:value-of select="Result/@end_display"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Tests Passed</td>
+ <td>
+ <xsl:value-of select="Result/Summary/@pass"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Tests Failed</td>
+ <td>
+ <xsl:value-of select="Result/Summary/@failed"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Tests Not Executed</td>
+ <td>
+ <xsl:value-of select="Result/Summary/@not_executed"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Modules Done</td>
+ <td>
+ <xsl:value-of select="Result/Summary/@modules_done"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Modules Total</td>
+ <td>
+ <xsl:value-of select="Result/Summary/@modules_total"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Fingerprint</td>
+ <td>
+ <xsl:value-of select="Result/Build/@build_fingerprint"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Security Patch</td>
+ <td>
+ <xsl:value-of select="Result/Build/@build_version_security_patch"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">Release (SDK)</td>
+ <td>
+ <xsl:value-of select="Result/Build/@build_version_release"/> (<xsl:value-of select="Result/Build/@build_version_sdk"/>)
+ </td>
+ </tr>
+ <tr>
+ <td class="rowtitle">ABIs</td>
+ <td>
+ <xsl:value-of select="Result/Build/@build_abis"/>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ <!-- High level summary of test execution -->
+ <br/>
+ <div>
+ <table class="testsummary">
+ <tr>
+ <th>Module</th>
+ <th>Passed</th>
+ <th>Failed</th>
+ <th>Not Executed</th>
+ <th>Total Tests</th>
+ </tr>
+ <xsl:for-each select="Result/Module">
+ <tr>
+ <td>
+ <xsl:if test="count(TestCase/Test[@result = 'fail']) > 0">
+ <xsl:variable name="href"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></xsl:variable>
+ <a href="#{$href}"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></a>
+ </xsl:if>
+ <xsl:if test="count(TestCase/Test[@result = 'fail']) < 1">
+ <xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/>
+ </xsl:if>
+ </td>
+ <td>
+ <xsl:value-of select="@pass"/>
+ </td>
+ <td>
+ <xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
+ </td>
+ <td>
+ <xsl:value-of select="count(TestCase/Test[@result = 'not_executed'])"/>
+ </td>
+ <td>
+ <xsl:value-of select="count(TestCase/Test[@result = 'fail']) + @pass + count(TestCase/Test[@result = 'not_executed']) "/>
+ </td>
+ </tr>
+ </xsl:for-each> <!-- end Module -->
+ </table>
+ </div>
+
+ <br/>
+ <xsl:call-template name="detailedTestReport">
+ <xsl:with-param name="resultFilter" select="'fail'" />
+ </xsl:call-template>
+
+ </body>
+ </html>
+ </xsl:template>
+
+ <xsl:template name="detailedTestReport">
+ <xsl:param name="resultFilter" />
+ <div>
+ <xsl:for-each select="Result/Module">
+ <xsl:if test="$resultFilter=''
+ or count(TestCase/Test[@result=$resultFilter]) > 0">
+
+ <table class="testdetails">
+ <tr>
+ <td class="module" colspan="3">
+ <xsl:variable name="href"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></xsl:variable>
+ <a name="{$href}"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></a>
+ </td>
+ </tr>
+
+ <tr>
+ <th width="30%">Test</th>
+ <th width="5%">Result</th>
+ <th>Details</th>
+ </tr>
+
+ <xsl:for-each select="TestCase">
+ <xsl:variable name="TestCase" select="."/>
+ <!-- test -->
+ <xsl:for-each select="Test">
+ <xsl:if test="$resultFilter='' or @result=$resultFilter">
+ <tr>
+ <td class="testname"> <xsl:value-of select="$TestCase/@name"/>#<xsl:value-of select="@name"/></td>
+
+ <!-- test results -->
+ <xsl:if test="@result='pass'">
+ <td class="pass">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </td>
+ <td class="failuredetails"/>
+ </xsl:if>
+
+ <xsl:if test="@result='fail'">
+ <td class="failed">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </td>
+ <td class="failuredetails">
+ <div class="details">
+ <xsl:value-of select="Failure/@message"/>
+ </div>
+ </td>
+ </xsl:if>
+
+ <xsl:if test="@result='not_executed'">
+ <td class="not_executed">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </td>
+ <td class="failuredetails"></td>
+ </xsl:if>
+ </tr> <!-- finished with a row -->
+ </xsl:if>
+ </xsl:for-each> <!-- end test -->
+ </xsl:for-each>
+ </table>
+ </xsl:if>
+ </xsl:for-each> <!-- end test Module -->
+ </div>
+ </xsl:template>
+
+ <!-- Take a delimited string and insert line breaks after a some number of elements. -->
+ <xsl:template name="formatDelimitedString">
+ <xsl:param name="string" />
+ <xsl:param name="numTokensPerRow" select="10" />
+ <xsl:param name="tokenIndex" select="1" />
+ <xsl:if test="$string">
+ <!-- Requires the last element to also have a delimiter after it. -->
+ <xsl:variable name="token" select="substring-before($string, ';')" />
+ <xsl:value-of select="$token" />
+ <xsl:text> </xsl:text>
+
+ <xsl:if test="$tokenIndex mod $numTokensPerRow = 0">
+ <br />
+ </xsl:if>
+
+ <xsl:call-template name="formatDelimitedString">
+ <xsl:with-param name="string" select="substring-after($string, ';')" />
+ <xsl:with-param name="numTokensPerRow" select="$numTokensPerRow" />
+ <xsl:with-param name="tokenIndex" select="$tokenIndex + 1" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
index 16bf486..fea9ce8 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -232,6 +232,13 @@
}
/**
+ * @return a {@link File} in the resultDir for counting expected test runs
+ */
+ public File getTestRunsFile() throws FileNotFoundException {
+ return new File(getResultDir(), "test_runs.txt");
+ }
+
+ /**
* @return a {@link String} to use for directory suffixes created from the given time.
*/
public static String getDirSuffix(long millis) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java
index cea6953..c4a1385 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java
@@ -64,26 +64,17 @@
*/
@Override
public void testRunStarted(String id, int numTests) {
- if (mModuleId == null || !mModuleId.equals(id)) {
- mModuleId = id;
- mTotalTestsInModule = numTests;
- // Reset counters
- mCurrentTestNum = 0;
- mPassedTests = 0;
- mFailedTests = 0;
- mNotExecutedTests = 0;
- mTestFailed = false;
- logMessage("Starting %s with %d test%s",
- id, mTotalTestsInModule, (mTotalTestsInModule > 1) ? "s" : "");
- } else {
- if (mNotExecutedTests == 0) {
- mTotalTestsInModule += numTests;
- } else {
- mTotalTestsInModule += Math.max(0, numTests - mNotExecutedTests);
- }
- logMessage("Continuing %s with %d test%s",
- id, mTotalTestsInModule, (mTotalTestsInModule > 1) ? "s" : "");
- }
+ boolean isRepeatModule = (mModuleId != null && mModuleId.equals(id));
+ mModuleId = id;
+ mTotalTestsInModule = numTests;
+ // Reset counters
+ mCurrentTestNum = 0;
+ mPassedTests = 0;
+ mFailedTests = 0;
+ mNotExecutedTests = 0;
+ mTestFailed = false;
+ logMessage("%s %s with %d test%s", (isRepeatModule) ? "Continuing" : "Starting", id,
+ mTotalTestsInModule, (mTotalTestsInModule > 1) ? "s" : "");
}
/**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index ec41baf..dc31b4e 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -17,6 +17,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.result.InvocationFailureHandler;
+import com.android.compatibility.common.tradefed.result.TestRunHandler;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest.RetryType;
import com.android.compatibility.common.util.ICaseResult;
@@ -247,27 +248,30 @@
*/
@Override
public void testRunStarted(String id, int numTests) {
- if (mCurrentModuleResult != null && mCurrentModuleResult.getId().equals(id)) {
- // In case we get another test run of a known module, update the complete
- // status to false to indicate it is not complete.
- if (mCurrentModuleResult.isDone()) {
- // modules run with HostTest treat each test class as a separate module.
- // TODO(aaronholden): remove this case when JarHostTest is no longer calls
- // testRunStarted for each test class.
- mTotalTestsInModule += numTests;
- } else {
- // treat new tests as not executed tests from current module
- mTotalTestsInModule +=
- Math.max(0, numTests - mCurrentModuleResult.getNotExecuted());
- }
+ if (mCurrentModuleResult != null && mCurrentModuleResult.getId().equals(id)
+ && mCurrentModuleResult.isDone()) {
+ // Modules run with JarHostTest treat each test class as a separate module,
+ // resulting in additional unexpected test runs.
+ // This case exists only for N
+ mTotalTestsInModule += numTests;
} else {
+ // Handle non-JarHostTest case
mCurrentModuleResult = mResult.getOrCreateModule(id);
- mTotalTestsInModule = numTests;
+ mModuleWasDone = mCurrentModuleResult.isDone();
+ if (!mModuleWasDone) {
+ // we only want to update testRun variables if the IModuleResult is not yet done
+ // otherwise leave testRun variables alone so isDone evaluates to true.
+ if (mCurrentModuleResult.getExpectedTestRuns() == 0) {
+ mCurrentModuleResult.setExpectedTestRuns(TestRunHandler.getTestRuns(
+ mBuildHelper, mCurrentModuleResult.getId()));
+ }
+ mCurrentModuleResult.addTestRun();
+ }
// Reset counters
+ mTotalTestsInModule = numTests;
mCurrentTestNum = 0;
}
- mModuleWasDone = mCurrentModuleResult.isDone();
- mCurrentModuleResult.setDone(false);
+ mCurrentModuleResult.inProgress(true);
}
/**
@@ -351,17 +355,30 @@
*/
@Override
public void testRunEnded(long elapsedTime, Map<String, String> metrics) {
+ mCurrentModuleResult.inProgress(false);
mCurrentModuleResult.addRuntime(elapsedTime);
- if (mCanMarkDone || mModuleWasDone) {
- // Only mark module done if status of the invocation allows it (mCanMarkDone) or module
- // was previously marked done (mModuleWasDone) and all expected tests are collected.
- // Expect mCurrentTestNum = mTotalTestsInModule, but use >= to be safe
- mCurrentModuleResult.setDone(mCurrentTestNum >= mTotalTestsInModule);
+ if (!mModuleWasDone) {
+ // Not executed count now represents an upper-bound for a fix to b/33211104.
+ // Only setNotExecuted this number if the module has already been completely executed.
+ int testCountDiff = Math.max(mTotalTestsInModule - mCurrentTestNum, 0);
+ if (isShardResultReporter()) {
+ // reset value, which is added to total count for master shard upon merge
+ mCurrentModuleResult.setNotExecuted(testCountDiff);
+ } else {
+ // increment value for master shard
+ mCurrentModuleResult.setNotExecuted(mCurrentModuleResult.getNotExecuted()
+ + testCountDiff);
+ }
+ if (mCanMarkDone) {
+ // Only mark module done if status of the invocation allows it (mCanMarkDone) and
+ // if module has not already been marked done.
+ mCurrentModuleResult.setDone(mCurrentTestNum >= mTotalTestsInModule);
+ }
}
- mCurrentModuleResult.setNotExecuted(Math.max(mTotalTestsInModule - mCurrentTestNum, 0));
if (isShardResultReporter()) {
// Forward module results to the master.
mMasterResultReporter.mergeModuleResult(mCurrentModuleResult);
+ mCurrentModuleResult.resetTestRuns();
}
}
@@ -473,7 +490,13 @@
mBuildHelper.getSuiteBuild(), mResult, mResultDir, startTime,
elapsedTime + startTime, mReferenceUrl, getLogUrl(),
mBuildHelper.getCommandLineArgs());
- info("Test Result: %s", resultFile.getCanonicalPath());
+ // Create failure report after zip file so extra data is not uploaded
+ File failureReport = ResultHandler.createFailureReport(resultFile);
+ if (failureReport.exists()) {
+ info("Test Result: %s", failureReport.getCanonicalPath());
+ } else {
+ info("Test Result: %s", resultFile.getCanonicalPath());
+ }
File zippedResults = zipResults(mResultDir);
debug("Full Result: %s", zippedResults.getCanonicalPath());
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
index 6b9b5e4..9dbbcbb 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
@@ -65,14 +65,6 @@
STATUS_MAP = Collections.unmodifiableMap(statusMap);
}
- // TODO(aaronholden): remove this temporary workaround for b/33090757
- private static final Set<String> MULTITEST_MODULES;
- static {
- Set<String> multiTestModuleSet = new HashSet<String>();
- multiTestModuleSet.add("CtsDeqpTestCases");
- MULTITEST_MODULES = Collections.unmodifiableSet(multiTestModuleSet);
- }
-
@Option (name = "name", shortName = 'n', description = "the name of the subplan to create",
importance=Importance.IF_UNSET)
private String mSubPlanName = null;
@@ -192,49 +184,7 @@
subPlan.addIncludeFilter(new TestFilter(mAbiName, mModuleName, mTestName).toString());
}
Set<TestStatus> statusesToRun = getStatusesToRun();
-
for (IModuleResult module : mResult.getModules()) {
-
- // TODO(aaronholden): remove this special case from SubPlanCreator, and filter
- // individual tests only when the module should run. Tracked by b/33211104
- if (MULTITEST_MODULES.contains(module.getName())) {
- // cannot check module.isDone() since this value is not accurate for modules
- // with multiple test configs. If we should run not-executed tests, include module
- // and exclude tests with status not in mResultTypes.
- TestFilter moduleFilter =
- new TestFilter(module.getAbi(), module.getName(), null /*test*/);
- if (mResultTypes.contains(NOT_EXECUTED)) {
- subPlan.addIncludeFilter(moduleFilter.toString());
- for (ICaseResult caseResult : module.getResults()) {
- for (ITestResult testResult : caseResult.getResults()) {
- if (!statusesToRun.contains(testResult.getResultStatus())) {
- TestFilter testExclude = new TestFilter(module.getAbi(),
- module.getName(), testResult.getFullName());
- subPlan.addExcludeFilter(testExclude.toString());
- }
- }
- }
- } else {
- // not running not-executed tests, only include executed tests
- if (shouldRunModule(module)) {
- // at least some executed tests will be included
- for (ICaseResult caseResult : module.getResults()) {
- for (ITestResult testResult : caseResult.getResults()) {
- if (statusesToRun.contains(testResult.getResultStatus())) {
- TestFilter testInclude = new TestFilter(module.getAbi(),
- module.getName(), testResult.getFullName());
- subPlan.addIncludeFilter(testInclude.toString());
- }
- }
- }
- } else {
- // no executed tests will be included, so exclude entire module
- subPlan.addExcludeFilter(moduleFilter.toString());
- }
- }
- continue;
- }
-
if (shouldRunModule(module)) {
TestFilter moduleInclude =
new TestFilter(module.getAbi(), module.getName(), null /*test*/);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/TestRunHandler.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/TestRunHandler.java
new file mode 100644
index 0000000..4473eb8
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/TestRunHandler.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 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.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * A helper class for setting and checking the number of expected test runs.
+ */
+public class TestRunHandler {
+
+ private static final String MAP_DELIMITER = "->";
+
+ /**
+ * Determine the number of expected test runs for the module
+ *
+ * @param buildHelper the {@link CompatibilityBuildHelper} from which to retrieve invocation
+ * failure file
+ * @return the number of expected test runs, or 1 if module is not found
+ */
+ public static int getTestRuns(final CompatibilityBuildHelper buildHelper, String id) {
+ try {
+ File f = buildHelper.getTestRunsFile();
+ if (!f.exists() || f.length() == 0) {
+ return 1; // test runs file doesn't exist, expect one test run by default
+ }
+ String mapString = FileUtil.readStringFromFile(f);
+ Map<String, Integer> map = stringToMap(mapString);
+ Integer testRuns = map.get(id);
+ return (testRuns == null) ? 1 : testRuns;
+ } catch (IOException e) {
+ CLog.e("Could not read test run file for session %s",
+ buildHelper.getDirSuffix(buildHelper.getStartTime()));
+ CLog.e(e);
+ return 1;
+ }
+ }
+
+ /**
+ * Write the number of expected test runs to the result's test run file.
+ *
+ * @param buildHelper the {@link CompatibilityBuildHelper} used to write the
+ * test run file
+ * @param testRuns a mapping of module names to number of test runs expected
+ */
+ public static void setTestRuns(final CompatibilityBuildHelper buildHelper,
+ Map<String, Integer> testRuns) {
+ try {
+ File f = buildHelper.getTestRunsFile();
+ if (!f.exists()) {
+ f.createNewFile();
+ }
+ FileUtil.writeToFile(mapToString(testRuns), f);
+ } catch (IOException e) {
+ CLog.e("Exception while writing test runs file.");
+ CLog.e(e);
+ }
+ }
+
+ private static String mapToString(Map<String, Integer> map) {
+ StringBuilder sb = new StringBuilder("");
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ sb.append(String.format("%s%s%d\n", entry.getKey(), MAP_DELIMITER, entry.getValue()));
+ }
+ return sb.toString();
+ }
+
+ private static Map<String, Integer> stringToMap(String str) {
+ Map<String, Integer> map = new HashMap<>();
+ for (String entry : str.split("\n")) {
+ String[] parts = entry.split(MAP_DELIMITER);
+ map.put(parts[0], Integer.parseInt(parts[1]));
+ }
+ return map;
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 50ee9d0..f1e2b38 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -41,6 +41,7 @@
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.ResultForwarder;
import com.android.tradefed.suite.checker.ISystemStatusChecker;
import com.android.tradefed.suite.checker.ISystemStatusCheckerReceiver;
import com.android.tradefed.testtype.Abi;
@@ -69,6 +70,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -353,6 +355,11 @@
// Get the tests to run in this shard
modules = mModuleRepo.getModules(getDevice().getSerialNumber(), mShardIndex);
}
+ // Update BuildInfo in each shard to store the original command-line arguments from
+ // the session to be retried. These arguments will be serialized in the report later.
+ if (mRetrySessionId != null) {
+ loadRetryCommandLineArgs(mRetrySessionId);
+ }
listener = new FailureListener(listener, getDevice(), mBugReportOnFailure,
mLogcatOnFailure, mScreenshotOnFailure, mRebootOnFailure, mMaxLogcatBytes);
@@ -445,11 +452,17 @@
if (checkers != null && !checkers.isEmpty()) {
runPreModuleCheck(module.getName(), checkers, mDevice, listener);
}
+ // Workaround to b/34202787: Add result forwarder that ensures module is reported
+ // with 0 tests if test runner doesn't report anything in this case.
+ // Necessary for solution to b/33289177, in which completed modules may sometimes
+ // not be marked done until retried with 0 tests.
+ ModuleResultForwarder moduleListener = new ModuleResultForwarder(listener);
try {
if (module.getTest() instanceof IBuildReceiver) {
((IBuildReceiver)module.getTest()).setBuild(mBuildHelper.getBuildInfo());
}
- module.run(listener);
+ module.run(moduleListener);
+ moduleListener.finish(module.getId());
} catch (DeviceUnresponsiveException due) {
// being able to catch a DeviceUnresponsiveException here implies that recovery
// was successful, and test execution should proceed to next module
@@ -604,6 +617,30 @@
}
/**
+ * Sets the retry command-line args to be stored in the BuildInfo and serialized into the
+ * report upon completion of the invocation.
+ */
+ void loadRetryCommandLineArgs(Integer sessionId) {
+ IInvocationResult result = null;
+ try {
+ result = ResultHandler.findResult(mBuildHelper.getResultsDir(), sessionId);
+ } catch (FileNotFoundException e) {
+ // We should never reach this point, because this method should only be called
+ // after setupFilters(), so result exists if we've gotten this far
+ throw new RuntimeException(e);
+ }
+ if (result == null) {
+ // Again, this should never happen
+ throw new IllegalArgumentException(String.format(
+ "Could not find session with id %d", sessionId));
+ }
+ String retryCommandLineArgs = result.getCommandLineArgs();
+ if (retryCommandLineArgs != null) {
+ mBuildHelper.setRetryCommandLineArgs(retryCommandLineArgs);
+ }
+ }
+
+ /**
* Sets the include/exclude filters up based on if a module name was given or whether this is a
* retry run.
*/
@@ -638,8 +675,6 @@
String retryCommandLineArgs = result.getCommandLineArgs();
if (retryCommandLineArgs != null) {
- // Copy the original command into the build helper so it can be serialized later
- mBuildHelper.setRetryCommandLineArgs(retryCommandLineArgs);
try {
// parse the command-line string from the result file and set options
ArgsOptionParser parser = new ArgsOptionParser(this);
@@ -773,4 +808,32 @@
public void setCollectTestsOnly(boolean collectTestsOnly) {
mCollectTestsOnly = collectTestsOnly;
}
+
+ private class ModuleResultForwarder extends ResultForwarder {
+
+ private boolean mTestRunStarted = false;
+ private ITestInvocationListener mListener;
+
+ public ModuleResultForwarder(ITestInvocationListener listener) {
+ super(listener);
+ mListener = listener;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testRunStarted(String name, int numTests) {
+ mListener.testRunStarted(name, numTests);
+ mTestRunStarted = true;
+ }
+
+ public void finish(String moduleId) {
+ if (!mTestRunStarted) {
+ mListener.testRunStarted(moduleId, 0);
+ mListener.testRunEnded(0, Collections.emptyMap());
+ }
+ }
+ }
+
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index 8b72acf..33627b2 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -16,6 +16,8 @@
package com.android.compatibility.common.tradefed.testtype;
import com.android.compatibility.common.tradefed.util.LinearPartition;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.result.TestRunHandler;
import com.android.compatibility.common.util.TestFilter;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.ConfigurationException;
@@ -204,6 +206,7 @@
throw new IllegalArgumentException(
String.format("No config files found in %s", testsDir.getAbsolutePath()));
}
+ Map<String, Integer> shardedTestCounts = new HashMap<>();
for (File configFile : configFiles) {
final String name = configFile.getName().replace(CONFIG_EXT, "");
final String[] pathArg = new String[] { configFile.getAbsolutePath() };
@@ -256,6 +259,9 @@
if (mTotalShards > 1) {
shardedTests = splitShardableTests(tests, buildInfo);
}
+ if (shardedTests.size() > 1) {
+ shardedTestCounts.put(id, shardedTests.size());
+ }
for (IRemoteTest test : shardedTests) {
addModuleDef(name, abi, test, pathArg);
}
@@ -265,6 +271,7 @@
configFile.getName()), e);
}
}
+ TestRunHandler.setTestRuns(new CompatibilityBuildHelper(buildInfo), shardedTestCounts);
}
private List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests, IBuildInfo buildInfo) {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
index 3342ba0..4eb48fc 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
@@ -44,4 +44,14 @@
+ "CTS unit tests configuration.", e.getMessage()));
}
}
+
+ /**
+ * Test to ensure that Zip dependency on the Apache Commons Compress coming from TradeFed is
+ * properly setup. This dependency is required for some utilities of TradeFed to work.
+ */
+ public void testDependencyCommonsCompress() throws Exception {
+ ClassLoader loader = ClassLoader.getSystemClassLoader();
+ // This will throw an exception if dependency isn't met.
+ loader.loadClass("org.apache.commons.compress.archivers.zip.ZipFile");
+ }
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java
index 2db94fa..272b94d 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java
@@ -90,15 +90,6 @@
assertEquals(0, mReporter.getPassedTests());
assertEquals(0, mReporter.getCurrentTestNum());
assertEquals(3, mReporter.getTotalTestsInModule());
-
- runTests();
- // Same id, should not reset test counters, but aggregate total tests
- mReporter.testRunStarted(ID2, 5);
- assertEquals(ID2, mReporter.getModuleId());
- assertEquals(2, mReporter.getFailedTests());
- assertEquals(1, mReporter.getPassedTests());
- assertEquals(3, mReporter.getCurrentTestNum());
- assertEquals(8, mReporter.getTotalTestsInModule());
}
/** Run 4 test, but one is ignored */
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
index 09885ed..5af79dc 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
@@ -296,7 +296,7 @@
// Set up IInvocationResult with existing results from previous session
IInvocationResult invocationResult = mReporter.getResult();
IModuleResult moduleResult = invocationResult.getOrCreateModule(ID);
- moduleResult.setDone(false);
+ moduleResult.initializeDone(false);
ICaseResult caseResult = moduleResult.getOrCreateResult(CLASS);
ITestResult testResult1 = caseResult.getOrCreateResult(METHOD_1);
testResult1.setResultStatus(TestStatus.PASS);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
index f341823..9793d8b 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -16,6 +16,8 @@
package com.android.compatibility.common.tradefed.testtype;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
import com.android.compatibility.common.tradefed.testtype.ModuleRepo.ConfigFilter;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -40,6 +42,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
@@ -75,6 +78,9 @@
private static final Set<String> EXCLUDES = new HashSet<>();
private static final Set<String> FILES = new HashSet<>();
private static final String FILENAME = "%s.config";
+ private static final String ROOT_DIR_ATTR = "ROOT_DIR";
+ private static final String SUITE_NAME_ATTR = "SUITE_NAME";
+ private static final String START_TIME_MS_ATTR = "START_TIME_MS";
private static final String ABI_32 = "armeabi-v7a";
private static final String ABI_64 = "arm64-v8a";
private static final String MODULE_NAME_A = "FooModuleA";
@@ -116,6 +122,7 @@
}
private ModuleRepo mRepo;
private File mTestsDir;
+ private File mRootDir;
private IBuildInfo mMockBuildInfo;
@Override
@@ -123,6 +130,19 @@
mTestsDir = setUpConfigs();
mRepo = new ModuleRepo();
mMockBuildInfo = EasyMock.createMock(IBuildInfo.class);
+ // Flesh out the result directory structure so ModuleRepo can write to the test runs file
+ mRootDir = FileUtil.createTempDir("root");
+ File subRootDir = new File(mRootDir, String.format("android-suite"));
+ File resultsDir = new File(subRootDir, "results");
+ File resultDir = new File(resultsDir, CompatibilityBuildHelper.getDirSuffix(0));
+ resultDir.mkdirs();
+
+ Map<String, String> mockBuildInfoMap = new HashMap<String, String>();
+ mockBuildInfoMap.put(ROOT_DIR_ATTR, mRootDir.getAbsolutePath());
+ mockBuildInfoMap.put(SUITE_NAME_ATTR, "suite");
+ mockBuildInfoMap.put(START_TIME_MS_ATTR, Long.toString(0));
+ EasyMock.expect(mMockBuildInfo.getBuildAttributes()).andReturn(mockBuildInfoMap).anyTimes();
+ EasyMock.replay(mMockBuildInfo);
}
private File setUpConfigs() throws IOException {
@@ -154,6 +174,12 @@
public void tearDown() throws Exception {
FileUtil.recursiveDelete(mTestsDir);
mRepo.resetModuleRepo();
+ tearDownConfigs(mTestsDir);
+ tearDownConfigs(mRootDir);
+ }
+
+ private void tearDownConfigs(File testsDir) {
+ FileUtil.recursiveDelete(testsDir);
}
public void testInitialization() throws Exception {
diff --git a/common/util/src/com/android/compatibility/common/util/IModuleResult.java b/common/util/src/com/android/compatibility/common/util/IModuleResult.java
index 7c6279c..06d66c0 100644
--- a/common/util/src/com/android/compatibility/common/util/IModuleResult.java
+++ b/common/util/src/com/android/compatibility/common/util/IModuleResult.java
@@ -32,17 +32,91 @@
long getRuntime();
- boolean isDone();
-
- void setDone(boolean done);
-
- boolean isPassed();
-
+ /**
+ * Get the estimate of not-executed tests for this module. This estimate is a maximum
+ * not-executed count, assuming all test runs have been started.
+ * @return estimate of not-executed tests
+ */
int getNotExecuted();
+ /**
+ * Set the estimate of not-executed tests for this module. This estimate is a maximum
+ * not-executed count, assuming all test runs have been started.
+ * @param estimate of not-executed tests
+ */
void setNotExecuted(int numTests);
/**
+ * Whether all expected tests have been executed and all expected test runs have been seen
+ * and completed.
+ *
+ * @return the comprehensive completeness status of the module
+ */
+ boolean isDone();
+
+ /**
+ * Whether all expected tests have been executed for the test runs seen so far.
+ *
+ * @return the completeness status of the module so far
+ */
+ boolean isDoneSoFar();
+
+ /**
+ * Explicitly sets the "done" status for this module. To be used when constructing this
+ * instance from an XML report. The done status for an {@link IModuleResult} can be changed
+ * indiscriminately by method setDone(boolean) immediately after a call to initializeDone,
+ * whereas the status may only be switched to false immediately after a call to setDone.
+ *
+ * @param done the initial completeness status of the module
+ */
+ void initializeDone(boolean done);
+
+ /**
+ * Sets the "done" status for this module. To be used after each test run for the module.
+ * After setDone is used once, subsequent calls to setDone will AND the given value with the
+ * existing done status value. Thus a module with "done" already set to false cannot be marked
+ * done unless re-initialized (see initializeDone).
+ *
+ * @param done the completeness status of the module for a test run
+ */
+ void setDone(boolean done);
+
+ /**
+ * Sets the "in-progress" status for this module. Useful for tracking completion of the module
+ * in the case that a test run begins but never ends.
+ *
+ * @param inProgress whether the module is currently in progress
+ */
+ void inProgress(boolean inProgress);
+
+ /**
+ * @return the number of expected test runs for this module in this invocation
+ */
+ int getExpectedTestRuns();
+
+ /**
+ * @param the number of expected test runs for this module in this invocation
+ */
+ void setExpectedTestRuns(int numRuns);
+
+ /**
+ * @return the number of test runs seen for this module in this invocation
+ */
+ int getTestRuns();
+
+ /**
+ * Adds to the count of test runs seen for this module in this invocation
+ */
+ void addTestRun();
+
+ /**
+ * Reset the count of test runs seen for this module in this invocation. Should be performed
+ * after merging the module into another module, so that future merges do not double-count the
+ * same test runs.
+ */
+ void resetTestRuns();
+
+ /**
* Gets a {@link ICaseResult} for the given testcase, creating it if it doesn't exist.
*
* @param caseName the name of the testcase eg <package-name><class-name>
diff --git a/common/util/src/com/android/compatibility/common/util/ModuleResult.java b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
index 0c43e93..60038cf 100644
--- a/common/util/src/com/android/compatibility/common/util/ModuleResult.java
+++ b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
@@ -28,7 +28,13 @@
private String mId;
private long mRuntime = 0;
+
+ /* Variables related to completion of the module */
private boolean mDone = false;
+ private boolean mHaveSetDone = false;
+ private boolean mInProgress = false;
+ private int mExpectedTestRuns = 0;
+ private int mActualTestRuns = 0;
private int mNotExecuted = 0;
private Map<String, ICaseResult> mResults = new HashMap<>();
@@ -46,7 +52,27 @@
*/
@Override
public boolean isDone() {
- return mDone;
+ return mDone && !mInProgress && (mActualTestRuns >= mExpectedTestRuns);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isDoneSoFar() {
+ return mDone && !mInProgress;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initializeDone(boolean done) {
+ mDone = done;
+ mHaveSetDone = false;
+ if (mDone) {
+ mNotExecuted = 0;
+ }
}
/**
@@ -54,15 +80,63 @@
*/
@Override
public void setDone(boolean done) {
- mDone = done;
+ if (mHaveSetDone) {
+ mDone &= done; // If we've already set done for this instance, AND the received value
+ } else {
+ mDone = done; // If done has only been initialized, overwrite the existing value
+ }
+ mHaveSetDone = true;
+ if (mDone) {
+ mNotExecuted = 0;
+ }
}
/**
* {@inheritDoc}
*/
@Override
- public boolean isPassed() {
- return mDone && countResults(TestStatus.FAIL) == 0;
+ public void inProgress(boolean inProgress) {
+ mInProgress = inProgress;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getExpectedTestRuns() {
+ return mExpectedTestRuns;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setExpectedTestRuns(int numRuns) {
+ mExpectedTestRuns = numRuns;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getTestRuns() {
+ return mActualTestRuns;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addTestRun() {
+ mActualTestRuns++;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void resetTestRuns() {
+ mActualTestRuns = 0;
}
/**
@@ -184,7 +258,12 @@
}
this.mRuntime += otherModuleResult.getRuntime();
- this.mDone = otherModuleResult.isDone();
+ this.mNotExecuted += otherModuleResult.getNotExecuted();
+ this.setDone(otherModuleResult.isDoneSoFar());
+ this.mActualTestRuns += otherModuleResult.getTestRuns();
+ // expected test runs are the same across shards, except for shards that do not run this
+ // module at least once (for which the value is not yet set).
+ this.mExpectedTestRuns = otherModuleResult.getExpectedTestRuns();
for (ICaseResult otherCaseResult : otherModuleResult.getResults()) {
ICaseResult caseResult = getOrCreateResult(otherCaseResult.getName());
caseResult.mergeFrom(otherCaseResult);
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index e30efdb..2c63ae4 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -29,6 +29,7 @@
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -42,7 +43,11 @@
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
-
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
/**
* Handles conversion of results to/from files.
*/
@@ -53,6 +58,8 @@
private static final String NS = null;
private static final String RESULT_FILE_VERSION = "5.0";
public static final String TEST_RESULT_FILE_NAME = "test_result.xml";
+ private static final String FAILURE_REPORT_NAME = "test_result_failures.html";
+ private static final String FAILURE_XSL_FILE_NAME = "compatibility_failures.xsl";
public static final String[] RESULT_RESOURCES = {
"compatibility_result.css",
@@ -83,7 +90,7 @@
private static final String LOG_URL_ATTR = "log_url";
private static final String MESSAGE_ATTR = "message";
private static final String MODULE_TAG = "Module";
- private static final String MODULES_EXECUTED_ATTR = "modules_done";
+ private static final String MODULES_DONE_ATTR = "modules_done";
private static final String MODULES_TOTAL_ATTR = "modules_total";
private static final String NAME_ATTR = "name";
private static final String NOT_EXECUTED_ATTR = "not_executed";
@@ -182,9 +189,9 @@
String moduleId = AbiUtils.createId(abi, name);
boolean done = Boolean.parseBoolean(parser.getAttributeValue(NS, DONE_ATTR));
IModuleResult module = invocation.getOrCreateModule(moduleId);
- module.setDone(done);
- int notExecuted =
- Integer.parseInt(parser.getAttributeValue(NS, NOT_EXECUTED_ATTR));
+ module.initializeDone(done);
+ int notExecuted = Integer.parseInt(
+ parser.getAttributeValue(NS, NOT_EXECUTED_ATTR));
module.setNotExecuted(notExecuted);
long runtime = Long.parseLong(parser.getAttributeValue(NS, RUNTIME_ATTR));
module.addRuntime(runtime);
@@ -244,7 +251,7 @@
&& !checksumReporter.containsModuleResult(
module, invocation.getBuildFingerprint());
if (checksumMismatch) {
- module.setDone(false);
+ module.initializeDone(false);
}
}
parser.require(XmlPullParser.END_TAG, NS, RESULT_TAG);
@@ -354,7 +361,7 @@
serializer.attribute(NS, PASS_ATTR, Integer.toString(passed));
serializer.attribute(NS, FAILED_ATTR, Integer.toString(failed));
serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(notExecuted));
- serializer.attribute(NS, MODULES_EXECUTED_ATTR,
+ serializer.attribute(NS, MODULES_DONE_ATTR,
Integer.toString(result.getModuleCompleteCount()));
serializer.attribute(NS, MODULES_TOTAL_ATTR,
Integer.toString(result.getModules().size()));
@@ -368,6 +375,8 @@
serializer.attribute(NS, RUNTIME_ATTR, String.valueOf(module.getRuntime()));
serializer.attribute(NS, DONE_ATTR, Boolean.toString(module.isDone()));
serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(module.getNotExecuted()));
+ serializer.attribute(NS, PASS_ATTR,
+ Integer.toString(module.countResults(TestStatus.PASS)));
for (ICaseResult cr : module.getResults()) {
serializer.startTag(NS, CASE_TAG);
serializer.attribute(NS, NAME_ATTR, cr.getName());
@@ -427,6 +436,22 @@
return resultFile;
}
+ /**
+ * Generate html report listing an failed tests
+ */
+ public static File createFailureReport(File inputXml) {
+ File failureReport = new File(inputXml.getParentFile(), FAILURE_REPORT_NAME);
+ try (InputStream xslStream = ResultHandler.class.getResourceAsStream(
+ String.format("/report/%s", FAILURE_XSL_FILE_NAME));
+ OutputStream outputStream = new FileOutputStream(failureReport)) {
+
+ Transformer transformer = TransformerFactory.newInstance().newTransformer(
+ new StreamSource(xslStream));
+ transformer.transform(new StreamSource(inputXml), new StreamResult(outputStream));
+ } catch (IOException | TransformerException ignored) { }
+ return failureReport;
+ }
+
private static void createChecksum(File resultDir, IInvocationResult invocationResult) {
RetryChecksumStatus retryStatus = invocationResult.getRetryChecksumStatus();
switch (retryStatus) {
diff --git a/hostsidetests/devicepolicy/app/AccountCheck/Auth/src/com/android/cts/devicepolicy/accountcheck/AccountCheckTest.java b/hostsidetests/devicepolicy/app/AccountCheck/Auth/src/com/android/cts/devicepolicy/accountcheck/AccountCheckTest.java
index 73c18af..62c0b0b 100644
--- a/hostsidetests/devicepolicy/app/AccountCheck/Auth/src/com/android/cts/devicepolicy/accountcheck/AccountCheckTest.java
+++ b/hostsidetests/devicepolicy/app/AccountCheck/Auth/src/com/android/cts/devicepolicy/accountcheck/AccountCheckTest.java
@@ -68,21 +68,21 @@
}
/**
- * Add an incompatible account, type A.
+ * Add an incompatible account, type A, no features.
*/
public void testAddIncompatibleA() throws Exception {
addAccount();
}
/**
- * Add an incompatible account, type B.
+ * Add an incompatible account, type B. Disallow feature only.
*/
public void testAddIncompatibleB() throws Exception {
addAccount(ACCOUNT_FEATURE_DISALLOWED);
}
/**
- * Add an incompatible account, type C.
+ * Add an incompatible account, type C. Has the disallow feature.
*/
public void testAddIncompatibleC() throws Exception {
addAccount(ACCOUNT_FEATURE_ALLOWED, ACCOUNT_FEATURE_DISALLOWED);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/RequiredStrongAuthTimeoutTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/RequiredStrongAuthTimeoutTest.java
new file mode 100644
index 0000000..c236093
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/RequiredStrongAuthTimeoutTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.content.ComponentName;
+
+import java.util.concurrent.TimeUnit;
+
+public class RequiredStrongAuthTimeoutTest extends BaseDeviceAdminTest {
+
+ private static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(72);
+ private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(1);
+ private static final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
+ private static final long MIN_PLUS_ONE_MINUTE = MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE;
+ private static final long MAX_MINUS_ONE_MINUTE = DEFAULT_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE;
+
+ private static final ComponentName ADMIN = ADMIN_RECEIVER_COMPONENT;
+
+ public void testSetRequiredStrongAuthTimeout() throws Exception {
+ // aggregation should be the default if unset by any admin
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(null),
+ DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // admin not participating by default
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(ADMIN), 0);
+
+ //clamping from the top
+ mDevicePolicyManager.setRequiredStrongAuthTimeout(ADMIN,
+ DEFAULT_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(ADMIN),
+ DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(null),
+ DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // 0 means the admin is not participating, so default should be returned
+ mDevicePolicyManager.setRequiredStrongAuthTimeout(ADMIN, 0);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(ADMIN), 0);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(null),
+ DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // clamping from the bottom
+ mDevicePolicyManager.setRequiredStrongAuthTimeout(ADMIN,
+ MINIMUM_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(ADMIN),
+ MINIMUM_STRONG_AUTH_TIMEOUT_MS);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(null),
+ MINIMUM_STRONG_AUTH_TIMEOUT_MS);
+
+ // values within range
+ mDevicePolicyManager.setRequiredStrongAuthTimeout(ADMIN, MIN_PLUS_ONE_MINUTE);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(ADMIN), MIN_PLUS_ONE_MINUTE);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(null), MIN_PLUS_ONE_MINUTE);
+
+ mDevicePolicyManager.setRequiredStrongAuthTimeout(ADMIN, MAX_MINUS_ONE_MINUTE);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(ADMIN),
+ MAX_MINUS_ONE_MINUTE);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE);
+
+ // reset to default
+ mDevicePolicyManager.setRequiredStrongAuthTimeout(ADMIN, 0);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(ADMIN), 0);
+ assertEquals(mDevicePolicyManager.getRequiredStrongAuthTimeout(null),
+ DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // negative value
+ try {
+ mDevicePolicyManager.setRequiredStrongAuthTimeout(ADMIN, -ONE_MINUTE);
+ fail("Didn't throw IllegalArgumentException");
+ } catch (IllegalArgumentException iae) {
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
index 628a2cd..918094c 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
+import android.view.WindowManager;
import java.lang.Override;
@@ -35,6 +36,7 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java
index 6541146..a90a3d5 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java
@@ -179,53 +179,54 @@
assertTestOnlyNotInstallable();
assertNonTestOnlyNotInstallable();
- // Incompatible, type B.
- removeAllAccounts();
- runTest("testAddIncompatibleB");
-
- assertTestOnlyNotInstallable();
- assertNonTestOnlyNotInstallable();
-
- // Incompatible, type C.
- removeAllAccounts();
- runTest("testAddIncompatibleC");
-
- assertTestOnlyNotInstallable();
- assertNonTestOnlyNotInstallable();
-
- // Compatible.
- removeAllAccounts();
- runTest("testAddCompatible");
-
- assertTestOnlyInstallable(); // Now test-only owner can be accepted.
- assertNonTestOnlyNotInstallable();
-
- // 2 compatible accounts.
- removeAllAccounts();
- runTest("testAddCompatible");
- runTest("testAddCompatible");
-
- assertTestOnlyInstallable(); // Now test-only owner can be accepted.
-
- assertNonTestOnlyNotInstallable();
-
- // 2 compatible accounts + 1 incompatible.
- removeAllAccounts();
- runTest("testAddIncompatibleA");
- runTest("testAddCompatible");
- runTest("testAddCompatible");
-
- assertTestOnlyNotInstallable();
- assertNonTestOnlyNotInstallable();
-
- // 2 compatible accounts + 1 incompatible, different order.
- removeAllAccounts();
- runTest("testAddCompatible");
- runTest("testAddCompatible");
- runTest("testAddIncompatibleB");
-
- assertTestOnlyNotInstallable();
- assertNonTestOnlyNotInstallable();
+ // The following tests use non-public strings, so disabled until they go public.
+// // Incompatible, type B.
+// removeAllAccounts();
+// runTest("testAddIncompatibleB");
+//
+// assertTestOnlyNotInstallable();
+// assertNonTestOnlyNotInstallable();
+//
+// // Incompatible, type C.
+// removeAllAccounts();
+// runTest("testAddIncompatibleC");
+//
+// assertTestOnlyNotInstallable();
+// assertNonTestOnlyNotInstallable();
+//
+// // Compatible.
+// removeAllAccounts();
+// runTest("testAddCompatible");
+//
+// assertTestOnlyInstallable(); // Now test-only owner can be accepted.
+// assertNonTestOnlyNotInstallable();
+//
+// // 2 compatible accounts.
+// removeAllAccounts();
+// runTest("testAddCompatible");
+// runTest("testAddCompatible");
+//
+// assertTestOnlyInstallable(); // Now test-only owner can be accepted.
+//
+// assertNonTestOnlyNotInstallable();
+//
+// // 2 compatible accounts + 1 incompatible.
+// removeAllAccounts();
+// runTest("testAddIncompatibleA");
+// runTest("testAddCompatible");
+// runTest("testAddCompatible");
+//
+// assertTestOnlyNotInstallable();
+// assertNonTestOnlyNotInstallable();
+//
+// // 2 compatible accounts + 1 incompatible, different order.
+// removeAllAccounts();
+// runTest("testAddCompatible");
+// runTest("testAddCompatible");
+// runTest("testAddIncompatibleB");
+//
+// assertTestOnlyNotInstallable();
+// assertNonTestOnlyNotInstallable();
} catch (Throwable th) {
CLog.w("Tests failed; current accounts are:");
CLog.w(getDevice().executeShellCommand("dumpsys account"));
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index c2ee3f7..c29b294 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -628,6 +628,13 @@
}
+ public void testRequiredStrongAuthTimeout() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ executeDeviceTestClass(".RequiredStrongAuthTimeoutTest");
+ }
+
protected void executeDeviceTestClass(String className) throws Exception {
runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId);
}
diff --git a/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java b/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java
index 185363c..7452d22 100644
--- a/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java
+++ b/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java
@@ -39,6 +39,12 @@
private static final String STATIC_LIB_PROVIDER4_APK = "CtsStaticSharedLibProviderApp4.apk";
private static final String STATIC_LIB_PROVIDER4_PKG = "android.os.lib.provider";
+ private static final String STATIC_LIB_PROVIDER5_APK = "CtsStaticSharedLibProviderApp5.apk";
+ private static final String STATIC_LIB_PROVIDER5_PKG = "android.os.lib.provider";
+
+ private static final String STATIC_LIB_PROVIDER6_APK = "CtsStaticSharedLibProviderApp6.apk";
+ private static final String STATIC_LIB_PROVIDER6_PKG = "android.os.lib.provider";
+
private static final String STATIC_LIB_CONSUMER1_APK = "CtsStaticSharedLibConsumerApp1.apk";
private static final String STATIC_LIB_CONSUMER1_PKG = "android.os.lib.consumer1";
@@ -224,6 +230,22 @@
}
}
+ public void testLibraryAndPackageNameCanMatch() throws Exception {
+ getDevice().uninstallPackage(STATIC_LIB_PROVIDER5_PKG);
+ getDevice().uninstallPackage(STATIC_LIB_PROVIDER6_PKG);
+ try {
+ // Install a library with same name as package should work.
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+ STATIC_LIB_PROVIDER5_APK), false, false));
+ // Install a library with same name as package should work.
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+ STATIC_LIB_PROVIDER6_APK), true, false));
+ } finally {
+ getDevice().uninstallPackage(STATIC_LIB_PROVIDER5_PKG);
+ getDevice().uninstallPackage(STATIC_LIB_PROVIDER6_PKG);
+ }
+ }
+
public void testGetSharedLibraries() throws Exception {
getDevice().uninstallPackage(STATIC_LIB_CONSUMER1_PKG);
getDevice().uninstallPackage(STATIC_LIB_CONSUMER2_PKG);
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.mk
new file mode 100644
index 0000000..a9df0f8
--- /dev/null
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := CtsStaticSharedLibProviderApp5
+
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_AAPT_FLAGS := --shared-lib
+
+LOCAL_EXPORT_PACKAGE_RESOURCES := true
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/AndroidManifest.xml b/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/AndroidManifest.xml
new file mode 100755
index 0000000..404a0fa
--- /dev/null
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp5/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.os.lib.provider"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:hasCode="false">
+ <static-library android:name="android.os.lib.provider_2" android:version="1"/>
+ </application>
+</manifest>
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.mk
new file mode 100644
index 0000000..3c06105
--- /dev/null
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := CtsStaticSharedLibProviderApp6
+
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_AAPT_FLAGS := --shared-lib
+
+LOCAL_EXPORT_PACKAGE_RESOURCES := true
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/AndroidManifest.xml b/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/AndroidManifest.xml
new file mode 100755
index 0000000..7619998f
--- /dev/null
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp6/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.os.lib.provider"
+ android:versionCode="2"
+ android:versionName="2.0">
+ <application android:hasCode="false">
+ <static-library android:name="android.os.lib.provider_2" android:version="2"/>
+ </application>
+</manifest>
diff --git a/hostsidetests/theme/assets/hdpi.zip b/hostsidetests/theme/assets/hdpi.zip
new file mode 100644
index 0000000..6cc2d50
--- /dev/null
+++ b/hostsidetests/theme/assets/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/mdpi.zip b/hostsidetests/theme/assets/mdpi.zip
new file mode 100644
index 0000000..a350ff6
--- /dev/null
+++ b/hostsidetests/theme/assets/mdpi.zip
Binary files differ
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 07dc354..910af71 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -781,7 +781,7 @@
} finally {
conn.stopMonitoring();
- cmd = "appops set " + SIMPLE_PACKAGE_NAME + " RUN_IN_BACKGROUND normal";
+ cmd = "appops set " + SIMPLE_PACKAGE_NAME + " RUN_IN_BACKGROUND allow";
result = SystemUtil.runShellCommand(getInstrumentation(), cmd);
am.removeOnUidImportanceListener(uidGoneListener);
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 979d18a..f03c549 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -474,6 +474,10 @@
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) &&
!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) &&
!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ // USB accessory mode is only a requirement for devices with USB ports supporting
+ // peripheral mode. As there is no public API to distinguish a device with only host
+ // mode support from having both peripheral and host support, the test may have
+ // false negatives.
assertAvailable(PackageManager.FEATURE_USB_ACCESSORY);
}
}
diff --git a/tests/tests/assist/common/src/android/assist/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
old mode 100644
new mode 100755
index 54416b4..3f98cb3
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -64,6 +64,7 @@
/** Flag Secure Test intent constants */
public static final String FLAG_SECURE_HASRESUMED = ACTION_PREFIX + "flag_secure_hasResumed";
public static final String APP_3P_HASRESUMED = ACTION_PREFIX + "app_3p_hasResumed";
+ public static final String APP_3P_HASDRAWED = ACTION_PREFIX + "app_3p_hasDrawed";
public static final String TEST_ACTIVITY_LOADED = ACTION_PREFIX + "test_activity_hasResumed";
/** Two second timeout for getting back assist context */
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
old mode 100644
new mode 100755
index d0a00c9..a34d09b
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -39,6 +39,7 @@
private BroadcastReceiver mReceiver;
private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+ private CountDownLatch mHasDrawedLatch = new CountDownLatch(1);
private CountDownLatch mReadyLatch = new CountDownLatch(1);
public AssistStructureTest() {
@@ -68,6 +69,7 @@
mReceiver = new AssistStructureTestBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Utils.APP_3P_HASRESUMED);
+ filter.addAction(Utils.APP_3P_HASDRAWED);
filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
mContext.registerReceiver(mReceiver, filter);
}
@@ -77,6 +79,15 @@
if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
}
+
+ }
+
+ private void waitForOnDraw() throws Exception {
+ Log.i(TAG, "waiting for onDraw() before continuing");
+ if (!mHasDrawedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Activity failed to draw in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+ }
+
}
public void testAssistStructure() throws Throwable {
@@ -88,6 +99,7 @@
mTestActivity.startTest(TEST_CASE_TYPE);
waitForAssistantToBeReady(mReadyLatch);
waitForOnResume();
+ waitForOnDraw();
startSession();
waitForContext();
getInstrumentation().waitForIdleSync();
@@ -112,6 +124,10 @@
if (mReadyLatch != null) {
mReadyLatch.countDown();
}
+ }else if (action.equals(Utils.APP_3P_HASDRAWED)) {
+ if (mHasDrawedLatch != null) {
+ mHasDrawedLatch.countDown();
+ }
}
}
}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
old mode 100644
new mode 100755
index e0f83cc..7ef9e8c
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
@@ -71,4 +71,10 @@
}
});
}
+
+ public void onEnterAnimationComplete() {
+ Log.i(TAG, "TestApp onEnterAnimationComplete ");
+ sendBroadcast(new Intent(Utils.APP_3P_HASDRAWED));
+ }
+
}
\ No newline at end of file
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 4e24981..5992add 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -173,6 +173,7 @@
assertFalse(cap.getDesiredMaxLuminance() < -1.0f);
assertFalse(cap.getDesiredMinLuminance() < -1.0f);
assertFalse(cap.getDesiredMaxAverageLuminance() < -1.0f);
+ assertFalse(display.isHdr());
}
/**
@@ -205,6 +206,8 @@
assertTrue(0 < display.getRefreshRate());
assertTrue(display.getName().contains(OVERLAY_DISPLAY_NAME_PREFIX));
+
+ assertFalse(display.isWideColorGamut());
}
/**
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index a4b57bd..e98063d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -774,6 +774,24 @@
}
@Test
+ public void testRestoreToCountExceptionBehavior() {
+ int restoreTo = mCanvas.save();
+ mCanvas.save();
+ int beforeCount = mCanvas.getSaveCount();
+
+ boolean exceptionObserved = false;
+ try {
+ mCanvas.restoreToCount(restoreTo - 1);
+ } catch (IllegalArgumentException e) {
+ exceptionObserved = true;
+ }
+
+ // restore to count threw, AND did no restoring
+ assertTrue(exceptionObserved);
+ assertEquals(beforeCount, mCanvas.getSaveCount());
+ }
+
+ @Test
public void testRestoreToCount() {
final Matrix m1 = new Matrix();
m1.setValues(values1);
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 723a3f8..6e14198 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 The Android Open Source Project
+# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,29 +14,34 @@
LOCAL_PATH:= $(call my-dir)
-# CtsHardwareTestCases package
-
include $(CLEAR_VARS)
+# don't include this package in any target
LOCAL_MODULE_TAGS := tests
-
+# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
-LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util \
- ctstestrunner \
- mockito-target-minus-junit4 \
- android-ex-camera2
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHardwareTestCases
-
-LOCAL_SDK_VERSION := current
+LOCAL_MULTILIB := both
LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ compatibility-device-util \
+ ctstestrunner \
+ mockito-target-minus-junit4 \
+ platform-test-annotations \
+ ub-uiautomator
+
+LOCAL_JNI_SHARED_LIBRARIES := libctshardware_jni libnativehelper_compat_libc++
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsHardwareTestCases
+
include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/hardware/jni/Android.mk b/tests/tests/hardware/jni/Android.mk
new file mode 100644
index 0000000..0cd95e7
--- /dev/null
+++ b/tests/tests/hardware/jni/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libctshardware_jni
+
+LOCAL_CFLAGS += -Werror
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ CtsHardwareJniOnLoad.cpp \
+ android_hardware_cts_HardwareBufferTest.cpp
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+
+LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog
+
+LOCAL_CXX_STL := libc++_static
+
+LOCAL_CLANG := true
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/hardware/jni/CtsHardwareJniOnLoad.cpp b/tests/tests/hardware/jni/CtsHardwareJniOnLoad.cpp
new file mode 100644
index 0000000..2f607c9
--- /dev/null
+++ b/tests/tests/hardware/jni/CtsHardwareJniOnLoad.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <stdio.h>
+
+extern int register_android_hardware_cts_HardwareBufferTest(JNIEnv*);
+
+jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
+ JNIEnv* env = nullptr;
+ if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
+ return JNI_ERR;
+ if (register_android_hardware_cts_HardwareBufferTest(env))
+ return JNI_ERR;
+ return JNI_VERSION_1_4;
+}
diff --git a/tests/tests/hardware/jni/android_hardware_cts_HardwareBufferTest.cpp b/tests/tests/hardware/jni/android_hardware_cts_HardwareBufferTest.cpp
new file mode 100644
index 0000000..59c1637
--- /dev/null
+++ b/tests/tests/hardware/jni/android_hardware_cts_HardwareBufferTest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <android/hardware_buffer.h>
+
+#include <jni.h>
+
+#include <android/hardware_buffer_jni.h>
+#include <utils/Errors.h>
+
+#define LOG_TAG "HardwareBufferTest"
+
+static jobject android_hardware_HardwareBuffer_nativeCreateHardwareBuffer(JNIEnv* env, jclass,
+ jint width, jint height, jint format, jint layers, jlong usage) {
+ AHardwareBuffer* buffer = NULL;
+ AHardwareBuffer_Desc desc;
+
+ desc.width = width;
+ desc.height = height;
+ desc.layers = layers;
+ desc.usage0 = usage;
+ desc.usage1 = 0;
+ desc.format = format;
+ int res = AHardwareBuffer_allocate(&desc, &buffer);
+ if (res == android::NO_ERROR) {
+ return AHardwareBuffer_toHardwareBuffer(env, buffer);
+ } else {
+ return 0;
+ }
+}
+
+static void android_hardware_HardwareBuffer_nativeReleaseHardwareBuffer(JNIEnv* env, jclass,
+ jobject hardwareBufferObj) {
+ AHardwareBuffer* buffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBufferObj);
+ AHardwareBuffer_release(buffer);
+}
+
+static JNINativeMethod gMethods[] = {
+ { "nativeCreateHardwareBuffer", "(IIIIJ)Landroid/hardware/HardwareBuffer;",
+ (void *) android_hardware_HardwareBuffer_nativeCreateHardwareBuffer },
+ { "nativeReleaseHardwareBuffer", "(Landroid/hardware/HardwareBuffer;)V",
+ (void *) android_hardware_HardwareBuffer_nativeReleaseHardwareBuffer },
+};
+
+int register_android_hardware_cts_HardwareBufferTest(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/hardware/cts/HardwareBufferTest");
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java b/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
new file mode 100644
index 0000000..6d1f0d1
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link HardwareBuffer}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HardwareBufferTest {
+ private static native HardwareBuffer nativeCreateHardwareBuffer(int width, int height,
+ int format, int layers, long usage);
+ private static native void nativeReleaseHardwareBuffer(HardwareBuffer hardwareBufferObj);
+
+ static {
+ System.loadLibrary("ctshardware_jni");
+ }
+
+ @Test
+ public void testCreate() {
+ HardwareBuffer buffer = HardwareBuffer.create(2, 4, HardwareBuffer.RGBA_8888, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ assertTrue(buffer != null);
+ assertEquals(2, buffer.getWidth());
+ assertEquals(4, buffer.getHeight());
+ assertEquals(HardwareBuffer.RGBA_8888, buffer.getFormat());
+ assertEquals(1, buffer.getLayers());
+ assertEquals(HardwareBuffer.USAGE0_CPU_READ, buffer.getUsage());
+
+ buffer = HardwareBuffer.create(2, 4, HardwareBuffer.RGBX_8888, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ assertEquals(HardwareBuffer.RGBX_8888, buffer.getFormat());
+ buffer = HardwareBuffer.create(2, 4, HardwareBuffer.RGB_888, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ assertEquals(HardwareBuffer.RGB_888, buffer.getFormat());
+ buffer = HardwareBuffer.create(2, 4, HardwareBuffer.RGB_565, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ assertEquals(HardwareBuffer.RGB_565, buffer.getFormat());
+ }
+
+ @Test
+ public void testCreateFailsWithInvalidArguments() {
+ HardwareBuffer buffer = null;
+ assertEquals(null, buffer);
+ try {
+ buffer = HardwareBuffer.create(0, 4, HardwareBuffer.RGB_888, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ } catch (IllegalArgumentException e) {}
+ assertEquals(null, buffer);
+ try {
+ buffer = HardwareBuffer.create(2, 0, HardwareBuffer.RGB_888, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ } catch (IllegalArgumentException e) {}
+ assertEquals(null, buffer);
+ try {
+ buffer = HardwareBuffer.create(2, 4, 0, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ } catch (IllegalArgumentException e) {}
+ assertEquals(null, buffer);
+ try {
+ buffer = HardwareBuffer.create(2, 4, HardwareBuffer.RGB_888, -1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ } catch (IllegalArgumentException e) {}
+ assertEquals(null, buffer);
+ }
+
+ @Test
+ public void testCreateFromNativeObject() {
+ HardwareBuffer buffer = nativeCreateHardwareBuffer(2, 4, HardwareBuffer.RGBA_8888, 1,
+ HardwareBuffer.USAGE0_CPU_READ);
+ assertTrue(buffer != null);
+ assertEquals(2, buffer.getWidth());
+ assertEquals(4, buffer.getHeight());
+ assertEquals(HardwareBuffer.RGBA_8888, buffer.getFormat());
+ assertEquals(1, buffer.getLayers());
+ assertEquals(HardwareBuffer.USAGE0_CPU_READ, buffer.getUsage());
+ nativeReleaseHardwareBuffer(buffer);
+ }
+}
diff --git a/tests/tests/nativehardware/Android.mk b/tests/tests/nativehardware/Android.mk
new file mode 100644
index 0000000..c19511e
--- /dev/null
+++ b/tests/tests/nativehardware/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build the unit tests.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= CtsNativeHardwareTestCases
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+#LOCAL_C_INCLUDES := \
+# $(call include-path-for, wilhelm) \
+# $(call include-path-for, wilhelm-ut)
+
+LOCAL_SRC_FILES := \
+ src/AHardwareBufferTest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid \
+ libutils \
+ liblog \
+
+LOCAL_STATIC_LIBRARIES := \
+ libgtest \
+
+LOCAL_CTS_TEST_PACKAGE := android.nativehardware
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/tests/tests/nativehardware/AndroidTest.xml b/tests/tests/nativehardware/AndroidTest.xml
new file mode 100644
index 0000000..8fec974
--- /dev/null
+++ b/tests/tests/nativehardware/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Native Hardware test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="CtsNativeHardwareTestCases->/data/local/tmp/CtsNativeHardwareTestCases" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="CtsNativeHardwareTestCases" />
+ <option name="runtime-hint" value="1s" />
+ </test>
+</configuration>
diff --git a/tests/tests/nativehardware/src/AHardwareBufferTest.cpp b/tests/tests/nativehardware/src/AHardwareBufferTest.cpp
new file mode 100644
index 0000000..37a51e4
--- /dev/null
+++ b/tests/tests/nativehardware/src/AHardwareBufferTest.cpp
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHardwareBuffer_test"
+//#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <android/hardware_buffer.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+// Helper routines for checking that allocation was successful; depend on
+// internal implementation details.
+static inline GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(
+ AHardwareBuffer* buffer) {
+ return reinterpret_cast<GraphicBuffer*>(buffer);
+}
+
+static inline AHardwareBuffer* GraphicBuffer_to_AHardwareBuffer(
+ GraphicBuffer* buffer) {
+ return reinterpret_cast<AHardwareBuffer*>(buffer);
+}
+
+// This function is temporarily necessary to convert between bit versions.
+static inline uint32_t convertGralloc1ToGralloc0UsageBits(uint64_t usage0,
+ uint64_t usage1) {
+ uint32_t bits = 0;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_CPU_READ)
+ bits |= GRALLOC_USAGE_SW_READ_RARELY;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN)
+ bits |= GRALLOC_USAGE_SW_READ_OFTEN;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_CPU_WRITE)
+ bits |= GRALLOC_USAGE_SW_WRITE_RARELY;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN)
+ bits |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE)
+ bits |= GRALLOC_USAGE_HW_TEXTURE;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT)
+ bits |= GRALLOC_USAGE_HW_RENDER;
+ // Not sure what this should be.
+ if (usage0 & AHARDWAREBUFFER_USAGE0_GPU_STORAGE_IMAGE) bits |= 0;
+ // Not sure what this should be.
+ if (usage0 & AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP) bits |= 0;
+ // Not yet supported in gralloc1.
+ // if (usage0 & AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER) bits |= 0;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE)
+ bits |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ if (usage0 & AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT)
+ bits |= GRALLOC_USAGE_PROTECTED;
+
+ (void)usage1;
+
+ return bits;
+}
+
+static uint32_t convertFromGraphicBufferFormat(uint32_t format) {
+ switch (format) {
+ case PIXEL_FORMAT_RGBA_8888:
+ return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+ case PIXEL_FORMAT_RGBA_FP16:
+ return AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT;
+ case PIXEL_FORMAT_RGBX_8888:
+ return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+ case PIXEL_FORMAT_RGB_565:
+ return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+ case PIXEL_FORMAT_RGB_888:
+ return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
+ default:
+ return 0;
+ }
+}
+
+static ::testing::AssertionResult BuildFailureMessage(uint32_t expected,
+ uint32_t actual, const char* type) {
+ return ::testing::AssertionFailure() << "Buffer " << type << " do not match"
+ << ": " << actual << " != " << expected;
+}
+
+static ::testing::AssertionResult CheckAHardwareBufferMatchesDesc(
+ AHardwareBuffer* abuffer, const AHardwareBuffer_Desc& desc) {
+ GraphicBuffer* buffer = AHardwareBuffer_to_GraphicBuffer(abuffer);
+ if (static_cast<uint32_t>(buffer->width) != desc.width)
+ return BuildFailureMessage(desc.width,
+ static_cast<uint32_t>(buffer->width), "widths");
+ if (static_cast<uint32_t>(buffer->height) != desc.height)
+ return BuildFailureMessage(desc.height,
+ static_cast<uint32_t>(buffer->height), "heights");
+ if (static_cast<uint32_t>(buffer->layerCount) != desc.layers)
+ return BuildFailureMessage(desc.layers,
+ static_cast<uint32_t>(buffer->layerCount), "layers");
+ if (static_cast<uint32_t>(buffer->usage) !=
+ convertGralloc1ToGralloc0UsageBits(desc.usage0, desc.usage1))
+ return BuildFailureMessage(
+ convertGralloc1ToGralloc0UsageBits(desc.usage0, desc.usage1),
+ static_cast<uint32_t>(buffer->usage), "usages");
+ if (convertFromGraphicBufferFormat(buffer->getPixelFormat()) != desc.format)
+ return BuildFailureMessage(desc.format,
+ static_cast<uint32_t>(buffer->format), "formats");
+ return ::testing::AssertionSuccess();
+}
+
+// Test that passing in NULL values to allocate works as expected.
+TEST(AHardwareBufferTest, AHardwareBuffer_allocate_FailsWithNullInput) {
+ AHardwareBuffer* buffer;
+ AHardwareBuffer_Desc desc;
+
+ memset(&desc, 0, sizeof(AHardwareBuffer_Desc));
+
+ int res = AHardwareBuffer_allocate(&desc, NULL);
+ EXPECT_EQ(BAD_VALUE, res);
+ res = AHardwareBuffer_allocate(NULL, &buffer);
+ EXPECT_EQ(BAD_VALUE, res);
+ res = AHardwareBuffer_allocate(NULL, NULL);
+ EXPECT_EQ(BAD_VALUE, res);
+}
+
+// Test that allocate can create an AHardwareBuffer correctly.
+TEST(AHardwareBufferTest, AHardwareBuffer_allocate_Succeeds) {
+ AHardwareBuffer* buffer = NULL;
+ AHardwareBuffer_Desc desc;
+
+ desc.width = 2;
+ desc.height = 4;
+ desc.layers = 1;
+ desc.usage0 = AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
+ desc.usage1 = 0;
+ desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+ int res = AHardwareBuffer_allocate(&desc, &buffer);
+ EXPECT_EQ(NO_ERROR, res);
+ EXPECT_TRUE(CheckAHardwareBufferMatchesDesc(buffer, desc));
+ AHardwareBuffer_release(buffer);
+ buffer = NULL;
+
+ desc.width = 4;
+ desc.height = 12;
+ desc.layers = 1;
+ desc.usage0 = AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
+ desc.usage1 = 0;
+ desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+ res = AHardwareBuffer_allocate(&desc, &buffer);
+ EXPECT_EQ(NO_ERROR, res);
+ GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+ EXPECT_TRUE(CheckAHardwareBufferMatchesDesc(buffer, desc));
+ AHardwareBuffer_release(buffer);
+}
+
+TEST(AHardwareBufferTest, AHardwareBuffer_describe_Succeeds) {
+ AHardwareBuffer* buffer = NULL;
+ AHardwareBuffer_Desc desc;
+
+ desc.width = 2;
+ desc.height = 4;
+ desc.layers = 1;
+ desc.usage0 = AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
+ desc.usage1 = 0;
+ desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+ int res = AHardwareBuffer_allocate(&desc, &buffer);
+ EXPECT_EQ(NO_ERROR, res);
+
+ AHardwareBuffer_Desc expected_desc;
+ memset(&expected_desc, 0, sizeof(AHardwareBuffer_Desc));
+ AHardwareBuffer_describe(NULL, &desc);
+ EXPECT_EQ(0U, expected_desc.width);
+ AHardwareBuffer_describe(buffer, NULL);
+ EXPECT_EQ(0U, expected_desc.width);
+ AHardwareBuffer_describe(buffer, &desc);
+ EXPECT_TRUE(CheckAHardwareBufferMatchesDesc(buffer, desc));
+
+ AHardwareBuffer_release(buffer);
+}
+
+struct ClientData {
+ const char* path;
+ AHardwareBuffer* buffer;
+ ClientData(const char* path_in, AHardwareBuffer* buffer_in)
+ : path(path_in), buffer(buffer_in) {}
+};
+
+static void* clientFunction(void* data) {
+ ClientData* pdata = reinterpret_cast<ClientData*>(data);
+
+ int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ GTEST_LOG_(ERROR) << "Client socket call failed: " << strerror(errno);
+ return reinterpret_cast<void*>(-1);
+ }
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, pdata->path);
+
+ if (connect(fd, reinterpret_cast<struct sockaddr*>(&addr),
+ sizeof(addr)) < 0) {
+ GTEST_LOG_(ERROR) << "Client connect call failed: " << strerror(errno);
+ return reinterpret_cast<void*>(-1);
+ }
+
+ int err = AHardwareBuffer_sendHandleToUnixSocket(pdata->buffer, fd);
+ EXPECT_EQ(NO_ERROR, err);
+ close(fd);
+ return 0;
+}
+
+TEST(AHardwareBufferTest, AHardwareBuffer_SendAndRecv_Succeeds) {
+ AHardwareBuffer* buffer = NULL;
+ AHardwareBuffer_Desc desc;
+
+ desc.width = 2;
+ desc.height = 4;
+ desc.layers = 1;
+ desc.usage0 = AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
+ desc.usage1 = 0;
+ desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+
+ // Test that an invalid buffer fails.
+ int err = AHardwareBuffer_sendHandleToUnixSocket(NULL, 0);
+ EXPECT_EQ(BAD_VALUE, err);
+ err = 0;
+ err = AHardwareBuffer_sendHandleToUnixSocket(buffer, 0);
+ EXPECT_EQ(BAD_VALUE, err);
+
+ // Allocate the buffer.
+ err = AHardwareBuffer_allocate(&desc, &buffer);
+ EXPECT_EQ(NO_ERROR, err);
+
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ ASSERT_LT(0, fd);
+
+ std::string tempFile = "/data/local/tmp/ahardwarebuffer_test_XXXXXX";
+ int tempFd = mkstemp(&tempFile[0]);
+ unlink(&tempFile[0]);
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, &tempFile[0]);
+
+ // Bind the server and listen on the socket.
+ ASSERT_NE(-1, bind(fd, reinterpret_cast<struct sockaddr*>(&addr),
+ sizeof(addr))) << strerror(errno);
+ ASSERT_EQ(0, listen(fd, 1)) << strerror(errno);
+
+ // Launch a client that will send the buffer back.
+ ClientData data(&tempFile[0], buffer);
+ pthread_t thread;
+ ASSERT_EQ(0, pthread_create(&thread, NULL, clientFunction, &data));
+
+ // Wait for the client to send the buffer.
+ int acceptFd = accept(fd, NULL, NULL);
+ ASSERT_LT(0, acceptFd) << strerror(errno);
+
+ // Receive the buffer.
+ err = AHardwareBuffer_recvHandleFromUnixSocket(acceptFd, NULL);
+ EXPECT_EQ(BAD_VALUE, err);
+
+ AHardwareBuffer* received = NULL;
+ err = AHardwareBuffer_recvHandleFromUnixSocket(acceptFd, &received);
+ EXPECT_EQ(NO_ERROR, err);
+ ASSERT_TRUE(received != NULL);
+ EXPECT_TRUE(CheckAHardwareBufferMatchesDesc(received, desc));
+
+ void* ret_val;
+ ASSERT_EQ(0, pthread_join(thread, &ret_val));
+ ASSERT_EQ(NULL, ret_val);
+ close(acceptFd);
+ close(fd);
+
+ AHardwareBuffer_release(buffer);
+ AHardwareBuffer_release(received);
+}
+
+TEST(AHardwareBufferTest, AHardwareBuffer_Lock_and_Unlock_Succeed) {
+ AHardwareBuffer* buffer = NULL;
+ AHardwareBuffer_Desc desc;
+
+ desc.width = 2;
+ desc.height = 4;
+ desc.layers = 1;
+ desc.usage0 = AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE |
+ AHARDWAREBUFFER_USAGE0_CPU_READ;
+ desc.usage1 = 0;
+ desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+
+ // Test that an invalid buffer fails.
+ int err = AHardwareBuffer_lock(NULL, 0, -1, NULL, NULL);
+ EXPECT_EQ(BAD_VALUE, err);
+ err = 0;
+
+ // Allocate the buffer.
+ err = AHardwareBuffer_allocate(&desc, &buffer);
+ EXPECT_EQ(NO_ERROR, err);
+ void* bufferData = NULL;
+ err = AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE0_CPU_READ, -1,
+ NULL, &bufferData);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_TRUE(bufferData != NULL);
+ int32_t fence = -1;
+ err = AHardwareBuffer_unlock(buffer, &fence);
+
+ AHardwareBuffer_release(buffer);
+}
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
index e2112aa..54c2371 100644
--- a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
@@ -31,6 +31,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collections;
/**
* Test the non-location-related functionality of TelephonyManager.
@@ -270,6 +271,48 @@
}
}
+ /**
+ * Verify that TelephonyManager.setAllowedCarriers requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
+ */
+ @Test
+ public void testSetAllowedCarriers() {
+ if (!mHasTelephony
+ || !getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY_CARRIERLOCK)) {
+ return;
+ }
+ try {
+ mTelephonyManager.setAllowedCarriers(0, Collections.emptyList());
+ fail("Able to set allowed carriers");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that TelephonyManager.getAllowedCarriers requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}.
+ */
+ @Test
+ public void testGetAllowedCarriers() {
+ if (!mHasTelephony
+ || !getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY_CARRIERLOCK)) {
+ return;
+ }
+ try {
+ mTelephonyManager.getAllowedCarriers(0);
+ fail("Able to get allowed carriers");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
private static Context getContext() {
return InstrumentationRegistry.getContext();
}
diff --git a/tests/tests/security/res/raw/bug_33251605.bmp b/tests/tests/security/res/raw/bug_33251605.bmp
new file mode 100644
index 0000000..0060ff4
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_33251605.bmp
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/BigRleTest.java b/tests/tests/security/src/android/security/cts/BigRleTest.java
new file mode 100644
index 0000000..f3c2302
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BigRleTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.test.AndroidTestCase;
+
+import java.io.InputStream;
+
+import android.security.cts.R;
+
+public class BigRleTest extends AndroidTestCase {
+ /**
+ * Verifies that the device does not run OOM decoding a particular RLE encoded BMP.
+ *
+ * This image reports that its encoded length is over 4 gigs. Prior to fixing issue 33251605,
+ * we attempted to allocate space for all the encoded data at once, resulting in OOM.
+ */
+ public void test_android_bug_33251605() {
+ InputStream exploitImage = mContext.getResources().openRawResource(R.raw.bug_33251605);
+ Bitmap bitmap = BitmapFactory.decodeStream(exploitImage);
+ }
+}
diff --git a/tests/tests/text/src/android/text/cts/FontManagerTest.java b/tests/tests/text/src/android/text/cts/FontManagerTest.java
new file mode 100644
index 0000000..69ea522
--- /dev/null
+++ b/tests/tests/text/src/android/text/cts/FontManagerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.text.cts;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.FontConfig;
+import android.text.FontManager;
+
+import java.io.FileDescriptor;
+import java.util.List;
+
+/**
+ * Tests {@link FontManager}.
+ */
+public class FontManagerTest extends AndroidTestCase {
+
+ private FontManager mFontManager;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mFontManager = (FontManager) getContext().getSystemService(Context.FONT_SERVICE);
+ }
+
+ @SmallTest
+ public void testGetSystemFontsData() {
+ FontConfig config = mFontManager.getSystemFonts();
+
+ assertNotNull(config);
+ assertTrue("There should at least be one font family", config.getFamilies().size() > 0);
+ for (int i = 0; i < config.getFamilies().size(); ++i) {
+ FontConfig.Family family = config.getFamilies().get(i);
+ assertTrue("Each font family should have at least one font",
+ family.getFonts().size() > 0);
+ for (int j = 0; j < family.getFonts().size(); ++j) {
+ FontConfig.Font font = family.getFonts().get(j);
+ assertNotNull("FontManager should provide a FileDescriptor for each system font",
+ font.getFd());
+ }
+ }
+ }
+
+ @SmallTest
+ public void testFileDescriptorsAreReadOnly() throws Exception {
+ FontConfig fc = mFontManager.getSystemFonts();
+
+ List<FontConfig.Family> families = fc.getFamilies();
+ for (int i = 0; i < families.size(); ++i) {
+ List<FontConfig.Font> fonts = families.get(i).getFonts();
+ for (int j = 0; j < fonts.size(); ++j) {
+ ParcelFileDescriptor pfd = fonts.get(j).getFd();
+ assertNotNull(pfd);
+ FileDescriptor fd = pfd.getFileDescriptor();
+ long size = Os.lseek(fd, 0, OsConstants.SEEK_END);
+ // Read only mapping should success.
+ long addr = Os.mmap(0, size, OsConstants.PROT_READ, OsConstants.MAP_SHARED, fd, 0);
+ Os.munmap(addr, size);
+
+ // Mapping with PROT_WRITE should fail with EPERM.
+ try {
+ Os.mmap(0, size, OsConstants.PROT_READ | OsConstants.PROT_WRITE,
+ OsConstants.MAP_SHARED, fd, 0);
+ fail();
+ } catch (ErrnoException e) {
+ // EPERM should be raised.
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index 954a84a..5cd2fec 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -235,27 +235,20 @@
assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
}
- // Tests for finding new groups don't look at geometrical properties of the views. For them,
+ // Tests for finding new cluster don't look at geometrical properties of the views. For them,
// only tab order is important, which is mTopLeft, mTopRight, mBottomLeft. mBottomRight isn't
// used.
- private void verifyNextGroup(
- int groupType, View currentGroup, int direction, View expectedNextGroup) {
- View actualNextGroup = mFocusFinder.findNextKeyboardNavigationGroup(
- groupType, mLayout, currentGroup, direction);
- assertEquals(expectedNextGroup, actualNextGroup);
+ private void verifyNextCluster(View currentCluster, int direction, View expectedNextCluster) {
+ View actualNextCluster = mFocusFinder.findNextKeyboardNavigationCluster(
+ mLayout, currentCluster, direction);
+ assertEquals(expectedNextCluster, actualNextCluster);
}
@Test
- public void testNoGroups() {
- // No views are marked as groups, so next group is always null.
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mTopRight, View.FOCUS_FORWARD, null);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mTopRight, View.FOCUS_BACKWARD, null);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mTopRight, View.FOCUS_FORWARD, null);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mTopRight, View.FOCUS_BACKWARD, null);
+ public void testNoClusters() {
+ // No views are marked as clusters, so next cluster is always null.
+ verifyNextCluster(mTopRight, View.FOCUS_FORWARD, null);
+ verifyNextCluster(mTopRight, View.FOCUS_BACKWARD, null);
}
@Test
@@ -265,59 +258,16 @@
mTopRight.setKeyboardNavigationCluster(true);
mBottomLeft.setKeyboardNavigationCluster(true);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_FORWARD, mTopLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mTopLeft, View.FOCUS_FORWARD, mTopRight);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mTopRight, View.FOCUS_FORWARD, mBottomLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mBottomLeft, View.FOCUS_FORWARD, mLayout);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mBottomRight, View.FOCUS_FORWARD, mLayout);
+ verifyNextCluster(null, View.FOCUS_FORWARD, mTopLeft);
+ verifyNextCluster(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+ verifyNextCluster(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
+ verifyNextCluster(mBottomLeft, View.FOCUS_FORWARD, mLayout);
+ verifyNextCluster(mBottomRight, View.FOCUS_FORWARD, mLayout);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_BACKWARD, mBottomLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mTopLeft, View.FOCUS_BACKWARD, mLayout);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mTopRight, View.FOCUS_BACKWARD, mTopLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mBottomLeft, View.FOCUS_BACKWARD,
- mTopRight);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, mBottomRight, View.FOCUS_BACKWARD, mLayout);
- }
-
- @Test
- public void testFindNextSection() {
- // Section navigation from all possible starting points in all directions.
- mTopLeft.setKeyboardNavigationSection(true);
- mTopRight.setKeyboardNavigationSection(true);
- mBottomLeft.setKeyboardNavigationSection(true);
-
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_FORWARD, mTopLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mTopLeft, View.FOCUS_FORWARD, mTopRight);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mTopRight, View.FOCUS_FORWARD, mBottomLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mBottomLeft, View.FOCUS_FORWARD, mTopLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mBottomRight, View.FOCUS_FORWARD, mTopLeft);
-
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_BACKWARD, mBottomLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mTopLeft, View.FOCUS_BACKWARD, mBottomLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mTopRight, View.FOCUS_BACKWARD, mTopLeft);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mBottomLeft, View.FOCUS_BACKWARD,
- mTopRight);
- verifyNextGroup(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, mBottomRight, View.FOCUS_BACKWARD,
- mBottomLeft);
+ verifyNextCluster(null, View.FOCUS_BACKWARD, mBottomLeft);
+ verifyNextCluster(mTopLeft, View.FOCUS_BACKWARD, mLayout);
+ verifyNextCluster(mTopRight, View.FOCUS_BACKWARD, mTopLeft);
+ verifyNextCluster(mBottomLeft, View.FOCUS_BACKWARD, mTopRight);
+ verifyNextCluster(mBottomRight, View.FOCUS_BACKWARD, mLayout);
}
}
diff --git a/tests/tests/view/src/android/view/cts/MockView.java b/tests/tests/view/src/android/view/cts/MockView.java
index 7938d64..022609a 100644
--- a/tests/tests/view/src/android/view/cts/MockView.java
+++ b/tests/tests/view/src/android/view/cts/MockView.java
@@ -71,6 +71,7 @@
private boolean mCalledOnKeyPreIme = false;
private boolean mCalledOnResolvePointerIcon = false;
private boolean mCalledOnVisibilityAggregated = false;
+ private boolean mCalledRequestFocus = false;
private int mOldWidth = -1;
private int mOldHeight = -1;
@@ -626,10 +627,20 @@
mLastAggregatedVisibility = isVisible;
}
+ @Override
+ public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
+ mCalledRequestFocus = true;
+ return super.requestFocus(direction, previouslyFocusedRect);
+ }
+
public boolean hasCalledOnVisibilityAggregated() {
return mCalledOnVisibilityAggregated;
}
+ public boolean hasCalledRequestFocus() {
+ return mCalledRequestFocus;
+ }
+
public boolean getLastAggregatedVisibility() {
return mLastAggregatedVisibility;
}
@@ -674,7 +685,7 @@
mCalledOnKeyPreIme = false;
mCalledOnResolvePointerIcon = false;
mCalledOnVisibilityAggregated = false;
- mCalledOnVisibilityAggregated = false;
+ mCalledRequestFocus = false;
mOldWidth = -1;
mOldHeight = -1;
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 868a398..5b8d17f 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -140,73 +140,37 @@
mMockViewGroup.setFocusable(true);
mMockViewGroup.addFocusables(list, 0);
assertEquals(2, list.size());
-
- // Group is a cluster.
- list.clear();
- mMockViewGroup.setKeyboardNavigationCluster(true);
- mMockViewGroup.addFocusables(list, View.FOCUS_FORWARD);
- assertEquals(0, list.size());
- mMockViewGroup.addFocusables(list, View.FOCUS_DOWN);
- assertEquals(2, list.size());
- list.clear();
- mTextView.requestFocus();
- mMockViewGroup.addFocusables(list, View.FOCUS_FORWARD);
- assertEquals(2, list.size());
}
@UiThreadTest
@Test
- public void testAddKeyboardNavigationGroups() {
+ public void testAddKeyboardNavigationClusters() {
View v1 = new MockView(mContext);
View v2 = new MockView(mContext);
mMockViewGroup.addView(v1);
mMockViewGroup.addView(v2);
- // No groups.
+ // No clusters.
ArrayList<View> list = new ArrayList<>();
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, list, 0);
- assertEquals(0, list.size());
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, list, 0);
+ mMockViewGroup.addKeyboardNavigationClusters(list, 0);
assertEquals(0, list.size());
- // Children are a section and a cluster.
+ // A cluster and a non-cluster child.
v1.setKeyboardNavigationCluster(true);
- v2.setKeyboardNavigationSection(true);
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, list, 0);
+ mMockViewGroup.addKeyboardNavigationClusters(list, 0);
assertEquals(1, list.size());
assertEquals(v1, list.get(0));
list.clear();
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, list, 0);
- assertEquals(1, list.size());
- assertEquals(v2, list.get(0));
- list.clear();
-
- // Nested groups. Should ignore children.
- mMockViewGroup.setKeyboardNavigationCluster(true);
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, list, 0);
- assertEquals(1, list.size());
- assertEquals(mMockViewGroup, list.get(0));
- list.clear();
- mMockViewGroup.setKeyboardNavigationCluster(false);
- mMockViewGroup.setKeyboardNavigationSection(true);
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, list, 0);
- assertEquals(1, list.size());
- assertEquals(mMockViewGroup, list.get(0));
- list.clear();
- mMockViewGroup.setKeyboardNavigationSection(false);
// Blocking descendants from getting focus also blocks group search.
mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, list, 0);
- assertEquals(0, list.size());
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, list, 0);
+ mMockViewGroup.addKeyboardNavigationClusters(list, 0);
assertEquals(0, list.size());
mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
// Testing the results ordering.
- v2.setKeyboardNavigationSection(false);
v2.setKeyboardNavigationCluster(true);
- mMockViewGroup.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, list, 0);
+ mMockViewGroup.addKeyboardNavigationClusters(list, 0);
assertEquals(2, list.size());
assertEquals(v1, list.get(0));
assertEquals(v2, list.get(1));
@@ -216,22 +180,14 @@
ViewGroup parent = new MockViewGroup(mContext);
parent.addView(mMockViewGroup);
mMockViewGroup.removeView(v2);
- v1.setKeyboardNavigationCluster(false);
- v1.setKeyboardNavigationSection(true);
- parent.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, list, 0);
+ parent.addKeyboardNavigationClusters(list, 0);
assertEquals(1, list.size());
assertEquals(v1, list.get(0));
list.clear();
- // Searching for sections doesn't enter clusters.
- mMockViewGroup.setKeyboardNavigationCluster(true);
- parent.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, list, 0);
- assertEquals(0, list.size());
- mMockViewGroup.setKeyboardNavigationCluster(false);
-
// Invisible children get ignored.
mMockViewGroup.setVisibility(View.GONE);
- parent.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, list, 0);
+ parent.addKeyboardNavigationClusters(list, 0);
assertEquals(0, list.size());
}
@@ -773,22 +729,6 @@
@UiThreadTest
@Test
- public void testFindFocusWithCluster() {
- // v1 is a cluster, so it doesn't accept focus from outside if it.
- View v1 = new MockView(mContext);
- v1.setFocusable(true);
- v1.setKeyboardNavigationCluster(true);
- View v2 = new MockView(mContext);
- v2.setFocusable(true);
- mMockViewGroup.addView(v1);
- mMockViewGroup.addView(v2);
-
- mMockViewGroup.requestFocus();
- assertSame(v2, mMockViewGroup.findFocus());
- }
-
- @UiThreadTest
- @Test
public void testFitSystemWindows() {
Rect rect = new Rect(1, 1, 100, 100);
assertFalse(mMockViewGroup.fitSystemWindows(rect));
@@ -849,28 +789,6 @@
@UiThreadTest
@Test
- public void testFocusSearchWithCluster() {
- // focusSearch for FORWARD treats cluster like a root.
- View view = new View(mContext);
- view.setFocusable(true);
- View auntView = new View(mContext);
- auntView.setFocusable(true);
- MockViewGroup viewParent = new MockViewGroup(mContext);
- viewParent.addView(view);
- mMockViewGroup.addView(viewParent);
- mMockViewGroup.addView(auntView);
- mMockViewGroup.returnActualFocusSearchResult = true;
- viewParent.returnActualFocusSearchResult = true;
- mMockViewGroup.setIsRootNamespace(true);
- view.requestFocus();
-
- assertSame(auntView, view.focusSearch(View.FOCUS_FORWARD));
- viewParent.setKeyboardNavigationCluster(true);
- assertSame(view, view.focusSearch(View.FOCUS_FORWARD));
- }
-
- @UiThreadTest
- @Test
public void testGatherTransparentRegion() {
Region region = new Region();
mMockTextView.setAnimation(new AlphaAnimation(mContext, null));
@@ -1526,21 +1444,94 @@
assertTrue(mMockViewGroup.isOnRequestFocusInDescendantsCalled);
}
+ private void setupRestoreDefaultFocus() {
+ // Mark 2 children as focusable and add to the parent, then mark the second one as focused
+ // by default.
+ mMockViewGroup = new MockViewGroup(mContext);
+ mMockTextView = new MockTextView(mContext);
+ mMockTextView.setFocusable(true);
+ mTextView = new TextView(mContext);
+ mTextView.setFocusable(true);
+ mMockViewGroup.addView(mMockTextView);
+ mMockViewGroup.addView(mTextView);
+ mTextView.setFocusedByDefault(true);
+ }
+
@UiThreadTest
@Test
- public void testRequestFocusWithCluster() {
- // requestFocus skips nested clusters.
- View v1 = new View(mContext);
- v1.setFocusable(true);
- View v2 = new View(mContext);
- v2.setFocusable(true);
- mMockViewGroup.addView(v1);
- mMockViewGroup.addView(v2);
+ public void testRestoreDefaultFocus() {
+ // Invoking restoreDefaultFocus with various conditions that affect the outcome.
+ setupRestoreDefaultFocus();
+ mTextView.setFocusedByDefault(false);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mMockTextView, mMockViewGroup.findFocus());
+ setupRestoreDefaultFocus();
+ mTextView.setKeyboardNavigationCluster(true);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mMockTextView, mMockViewGroup.findFocus());
+
+ setupRestoreDefaultFocus();
+ mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
assertSame(null, mMockViewGroup.findFocus());
- v1.setKeyboardNavigationCluster(true);
- assertTrue(mMockViewGroup.requestFocus());
- assertSame(v2, mMockViewGroup.findFocus());
+
+ setupRestoreDefaultFocus();
+ mTextView.setVisibility(View.INVISIBLE);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mMockTextView, mMockViewGroup.findFocus());
+
+ setupRestoreDefaultFocus();
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mTextView, mMockViewGroup.findFocus());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testDefaultFocusViewRemoved() {
+ // Removing default-focus view from its parent in various ways.
+ setupRestoreDefaultFocus();
+ mMockViewGroup.removeView(mTextView);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mMockTextView, mMockViewGroup.findFocus());
+
+ setupRestoreDefaultFocus();
+ mMockViewGroup.removeViews(1, 1);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mMockTextView, mMockViewGroup.findFocus());
+
+ setupRestoreDefaultFocus();
+ mMockViewGroup.removeAllViewsInLayout();
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(null, mMockViewGroup.findFocus());
+
+ setupRestoreDefaultFocus();
+ mMockViewGroup.detachViewFromParent(mTextView);
+ mMockViewGroup.attachViewToParent(mTextView, 1, null);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mTextView, mMockViewGroup.findFocus());
+
+ setupRestoreDefaultFocus();
+ mMockViewGroup.detachViewFromParent(mTextView);
+ mMockViewGroup.removeDetachedView(mTextView, false);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertSame(mMockTextView, mMockViewGroup.findFocus());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testAddViewWithDefaultFocus() {
+ // Adding a view that has default focus propagates the default focus chain to the root.
+ mMockViewGroup = new MockViewGroup(mContext);
+ mMockTextView = new MockTextView(mContext);
+ mMockTextView.setFocusable(true);
+ mTextView = new TextView(mContext);
+ mTextView.setFocusable(true);
+ mTextView.setFocusedByDefault(true);
+ mMockViewGroup.addView(mMockTextView);
+ mMockViewGroup.addView(mTextView);
+ mMockViewGroup.restoreDefaultFocus(View.FOCUS_FORWARD);
+ assertTrue(mTextView.isFocused());
}
@UiThreadTest
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 6512f1b..472d660 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -1204,45 +1204,24 @@
}
@Test
- public void testAddKeyboardNavigationGroups() {
+ public void testAddKeyboardNavigationClusters() {
View view = new View(mActivity);
ArrayList<View> viewList = new ArrayList<>();
- // View is not a keyboard navigation group
+ // View is not a keyboard navigation cluster
assertFalse(view.isKeyboardNavigationCluster());
- assertFalse(view.isKeyboardNavigationSection());
- assertEquals(0, viewList.size());
-
- view.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, viewList, 0);
- assertEquals(0, viewList.size());
-
- view.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, viewList, 0);
+ view.addKeyboardNavigationClusters(viewList, 0);
assertEquals(0, viewList.size());
// View is a cluster
view.setKeyboardNavigationCluster(true);
- view.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, viewList, 0);
- assertEquals(0, viewList.size());
-
- view.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, viewList, 0);
- assertEquals(1, viewList.size());
- assertEquals(view, viewList.get(0));
-
- viewList.clear();
- view.setKeyboardNavigationCluster(false);
-
- // View is a section
- view.setKeyboardNavigationSection(true);
- view.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, viewList, 0);
- assertEquals(0, viewList.size());
-
- view.addKeyboardNavigationGroups(View.KEYBOARD_NAVIGATION_GROUP_SECTION, viewList, 0);
+ view.addKeyboardNavigationClusters(viewList, 0);
assertEquals(1, viewList.size());
assertEquals(view, viewList.get(0));
}
@Test
- public void testKeyboardNavigationGroupSearch() {
+ public void testKeyboardNavigationClusterSearch() {
mMockParent.setIsRootNamespace(true);
View v1 = new MockView(mActivity);
View v2 = new MockView(mActivity);
@@ -1252,55 +1231,20 @@
// Searching for clusters.
v1.setKeyboardNavigationCluster(true);
v2.setKeyboardNavigationCluster(true);
- assertEquals(v2, mMockParent.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, v1, View.FOCUS_FORWARD));
- assertEquals(v1, mMockParent.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_FORWARD));
- assertEquals(v2, mMockParent.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_BACKWARD));
- assertEquals(v2, v1.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_FORWARD));
- assertEquals(mMockParent, v1.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_BACKWARD));
- assertEquals(mMockParent, v2.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_FORWARD));
- assertEquals(v1, v2.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_CLUSTER, null, View.FOCUS_BACKWARD));
- v1.setKeyboardNavigationCluster(false);
- v2.setKeyboardNavigationCluster(false);
+ assertEquals(v2, mMockParent.keyboardNavigationClusterSearch(v1, View.FOCUS_FORWARD));
+ assertEquals(v1, mMockParent.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+ assertEquals(v2, mMockParent.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
+ assertEquals(v2, v1.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+ assertEquals(mMockParent, v1.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
+ assertEquals(mMockParent, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
+ assertEquals(v1, v2.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
- // Searching for sections.
- v1.setKeyboardNavigationSection(true);
- v2.setKeyboardNavigationSection(true);
- assertEquals(v2, mMockParent.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, v1, View.FOCUS_FORWARD));
- assertEquals(v1, mMockParent.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_FORWARD));
- assertEquals(v2, mMockParent.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_BACKWARD));
- assertEquals(v2, v1.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_FORWARD));
- assertEquals(v2, v1.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_BACKWARD));
- assertEquals(v1, v2.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_FORWARD));
- assertEquals(v1, v2.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_BACKWARD));
-
- // Sections in 3-level hierarchy.
+ // Clusters in 3-level hierarchy.
ViewGroup root = new MockViewParent(mActivity);
root.setIsRootNamespace(true);
- View auntSection = new MockView(mActivity);
- auntSection.setKeyboardNavigationSection(true);
- root.addView(auntSection);
mMockParent.setIsRootNamespace(false);
root.addView(mMockParent);
-
- assertEquals(auntSection, v2.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_FORWARD));
- mMockParent.setKeyboardNavigationCluster(true);
- assertEquals(v1, v2.keyboardNavigationGroupSearch(
- View.KEYBOARD_NAVIGATION_GROUP_SECTION, null, View.FOCUS_FORWARD));
+ assertEquals(root, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
}
@Test
@@ -2924,6 +2868,14 @@
assertTrue(view.hasCalledOnFocusChanged());
}
+ @UiThreadTest
+ @Test
+ public void testRestoreDefaultFocus() {
+ MockView view = new MockView(mActivity);
+ view.restoreDefaultFocus(0);
+ assertTrue(view.hasCalledRequestFocus());
+ }
+
@Test
public void testDrawableState() {
MockView view = new MockView(mActivity);
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index e102ec5..21438d5 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -6287,6 +6287,31 @@
verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
}
+ @UiThreadTest
+ @Test
+ public void testOnInitializeA11yNodeInfo_populatesHintTextProperly() {
+ final TextView textView = new TextView(mActivity);
+ textView.setText("", BufferType.EDITABLE);
+ final String hintText = "Hint text";
+ textView.setHint(hintText);
+ AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ textView.onInitializeAccessibilityNodeInfo(info);
+ assertTrue("Hint text flag set incorrectly for accessibility", info.isShowingHintText());
+ assertTrue("Hint text not showing as accessibility text",
+ TextUtils.equals(hintText, info.getText()));
+ assertTrue("Hint text not provided to accessibility",
+ TextUtils.equals(hintText, info.getHintText()));
+
+ final String nonHintText = "Something else";
+ textView.setText(nonHintText, BufferType.EDITABLE);
+ textView.onInitializeAccessibilityNodeInfo(info);
+ assertFalse("Hint text flag set incorrectly for accessibility", info.isShowingHintText());
+ assertTrue("Text not provided to accessibility",
+ TextUtils.equals(nonHintText, info.getText()));
+ assertTrue("Hint text not provided to accessibility",
+ TextUtils.equals(hintText, info.getHintText()));
+ }
+
@Test
public void testAutoSizeCallers_setCompoundDrawables() throws Throwable {
final TextView autoSizeTextView = prepareAndRetrieveAutoSizeTestData(
@@ -6592,41 +6617,140 @@
DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
TextView autoSizeTextViewXY = (TextView) mActivity.findViewById(R.id.textview_autosize_xy);
- // The size has been set to 50dp in the layout but this being an AUTO_SIZE_TYPE_XY TextView,
- // the size is considered max size thus the value returned by getSize() in this case should
- // be lower than the one set (given that there is not much available space and the font size
- // is very high). In theory the values could be equal for a different TextView
+ // The size has been set to 50dp in the layout but this being an AUTO_SIZE_TEXT_TYPE_XY
+ // TextView, the size is considered max size thus the value returned by getSize() in this
+ // case should be lower than the one set (given that there is not much available space and
+ // the font size is very high). In theory the values could be equal for a different TextView
// configuration.
final float sizeSetInPixels = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50f, metrics);
assertTrue(autoSizeTextViewXY.getTextSize() < sizeSetInPixels);
}
- @UiThreadTest
@Test
- public void testOnInitializeA11yNodeInfo_populatesHintTextProperly() {
+ public void testAutoSizeXY_getSetAutoSizeTextXY_defaults() {
final TextView textView = new TextView(mActivity);
- textView.setText("", BufferType.EDITABLE);
- final String hintText = "Hint text";
- textView.setHint(hintText);
- AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
- textView.onInitializeAccessibilityNodeInfo(info);
- assertTrue("Hint text flag set incorrectly for accessibility", info.isShowingHintText());
- assertTrue("Hint text not showing as accessibility text",
- TextUtils.equals(hintText, info.getText()));
- assertTrue("Hint text not provided to accessibility",
- TextUtils.equals(hintText, info.getHintText()));
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_NONE, textView.getAutoSizeTextType());
+ // Min/Max/Granularity values for auto-sizing are 0 because they are not used.
+ assertEquals(0, textView.getAutoSizeMinTextSize());
+ assertEquals(0, textView.getAutoSizeMaxTextSize());
+ assertEquals(0, textView.getAutoSizeStepGranularity());
- final String nonHintText = "Something else";
- textView.setText(nonHintText, BufferType.EDITABLE);
- textView.onInitializeAccessibilityNodeInfo(info);
- assertFalse("Hint text flag set incorrectly for accessibility", info.isShowingHintText());
- assertTrue("Text not provided to accessibility",
- TextUtils.equals(nonHintText, info.getText()));
- assertTrue("Hint text not provided to accessibility",
- TextUtils.equals(hintText, info.getHintText()));
+ textView.setAutoSizeTextType(TextView.AUTO_SIZE_TEXT_TYPE_XY);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_XY, textView.getAutoSizeTextType());
+ // Min/Max default values for auto-sizing XY have been loaded.
+ final int minSize = textView.getAutoSizeMinTextSize();
+ assertNotEquals(0, minSize);
+ final int maxSize = textView.getAutoSizeMaxTextSize();
+ assertNotEquals(0, maxSize);
+ assertTrue(minSize < maxSize);
+ final int stepGranularity = textView.getAutoSizeStepGranularity();
+ assertNotEquals(0, stepGranularity);
+
+ textView.setAutoSizeTextType(TextView.AUTO_SIZE_TEXT_TYPE_NONE);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_NONE, textView.getAutoSizeTextType());
+ // Min/Max values for auto-sizing XY have been cleared.
+ assertEquals(0, textView.getAutoSizeMinTextSize());
+ assertEquals(0, textView.getAutoSizeMaxTextSize());
+ assertEquals(0, textView.getAutoSizeStepGranularity());
}
+ @Test
+ public void testAutoSizeXY_getSetAutoSizeStepGranularity() {
+ final TextView textView = new TextView(mActivity);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_NONE, textView.getAutoSizeTextType());
+ final int initialValue = 0;
+ assertEquals(initialValue, textView.getAutoSizeStepGranularity());
+
+ textView.setAutoSizeTextType(TextView.AUTO_SIZE_TEXT_TYPE_XY);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_XY, textView.getAutoSizeTextType());
+ final int defaultValue = 1; // 1px.
+ // If the auto-size type is AUTO_SIZE_TEXT_TYPE_XY then it means textView went through the
+ // auto-size setup and given that 0 is an invalid value it changed it to the default.
+ assertEquals(defaultValue, textView.getAutoSizeStepGranularity());
+
+ final int newValue = 33;
+ textView.setAutoSizeStepGranularity(TypedValue.COMPLEX_UNIT_PX, newValue);
+ assertEquals(newValue, textView.getAutoSizeStepGranularity());
+ }
+
+ @Test
+ public void testAutoSizeXY_getSetAutoSizeMinTextSize() {
+ final TextView textView = new TextView(mActivity);
+ textView.setAutoSizeTextType(TextView.AUTO_SIZE_TEXT_TYPE_XY);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_XY, textView.getAutoSizeTextType());
+ final int minSize = textView.getAutoSizeMinTextSize();
+ assertNotEquals(0, minSize);
+ final int maxSize = textView.getAutoSizeMaxTextSize();
+ assertNotEquals(0, maxSize);
+
+ // This is just a test check to verify the next assertions. If this fails it is a problem
+ // of this test setup (we need at least 2 units).
+ assertTrue((maxSize - minSize) > 1);
+ final int newMinSize = maxSize - 1;
+ textView.setAutoSizeMinTextSize(TypedValue.COMPLEX_UNIT_PX, newMinSize);
+ assertEquals(newMinSize, textView.getAutoSizeMinTextSize());
+ // Max size has not changed.
+ assertEquals(maxSize, textView.getAutoSizeMaxTextSize());
+
+ // Prevent validation error (max <= min).
+ textView.setAutoSizeMaxTextSize(TypedValue.COMPLEX_UNIT_SP, newMinSize + 10);
+ textView.setAutoSizeMinTextSize(TypedValue.COMPLEX_UNIT_SP, newMinSize);
+ // It does not matter which unit has been used to set the min size, the getter always
+ // returns it in pixels.
+ assertEquals((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, newMinSize,
+ mActivity.getResources().getDisplayMetrics()), textView.getAutoSizeMinTextSize());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testAutoSizeXY_throwsException_whenMaxLessThanMin() {
+ final TextView textView = new TextView(mActivity);
+ textView.setAutoSizeTextType(TextView.AUTO_SIZE_TEXT_TYPE_XY);
+ textView.setAutoSizeMinTextSize(TypedValue.COMPLEX_UNIT_PX, 10);
+ // Should throw IllegalStateException here (because min > max).
+ textView.setAutoSizeMaxTextSize(TypedValue.COMPLEX_UNIT_PX, 9);
+ }
+
+ @Test
+ public void testAutoSizeXY_getSetAutoSizeMaxTextSize() {
+ final TextView textView = new TextView(mActivity);
+ textView.setAutoSizeTextType(TextView.AUTO_SIZE_TEXT_TYPE_XY);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_XY, textView.getAutoSizeTextType());
+ final int minSize = textView.getAutoSizeMinTextSize();
+ assertNotEquals(0, minSize);
+ final int maxSize = textView.getAutoSizeMaxTextSize();
+ assertNotEquals(0, maxSize);
+
+ final int newMaxSize = maxSize + 11;
+ textView.setAutoSizeMaxTextSize(TypedValue.COMPLEX_UNIT_PX, newMaxSize);
+ assertEquals(newMaxSize, textView.getAutoSizeMaxTextSize());
+ // Min size has not changed.
+ assertEquals(minSize, textView.getAutoSizeMinTextSize());
+
+ textView.setAutoSizeMaxTextSize(TypedValue.COMPLEX_UNIT_SP, newMaxSize);
+ // It does not matter which unit has been used to set the max size, the getter always
+ // returns it in pixels.
+ assertEquals((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, newMaxSize,
+ mActivity.getResources().getDisplayMetrics()), textView.getAutoSizeMaxTextSize());
+ }
+
+ @Test
+ public void testAutoSizeXY_autoSizeCalledWhenTypeChanged() throws Throwable {
+ mTextView = findTextView(R.id.textview_text);
+ // Make sure we pick an already inflated non auto-sized text view.
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_NONE, mTextView.getAutoSizeTextType());
+ // Set the text size to a very low value in order to prepare for auto-size.
+ final int customTextSize = 3;
+ mActivityRule.runOnUiThread(() ->
+ mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, customTextSize));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(customTextSize, mTextView.getTextSize(), 0f);
+ mActivityRule.runOnUiThread(() ->
+ mTextView.setAutoSizeTextType(TextView.AUTO_SIZE_TEXT_TYPE_XY));
+ mInstrumentation.waitForIdleSync();
+ // The size of the text should have changed.
+ assertNotEquals(customTextSize, mTextView.getTextSize(), 0f);
+ }
/**
* Some TextView attributes require non-fixed width and/or layout height. This function removes