Merge "Allow to skip the recents redaction tests if overview button is absent"
diff --git a/apps/CtsVerifier/res/values-vrheadset/strings.xml b/apps/CtsVerifier/res/values-vrheadset/strings.xml
index c92038d..fef8d7f 100644
--- a/apps/CtsVerifier/res/values-vrheadset/strings.xml
+++ b/apps/CtsVerifier/res/values-vrheadset/strings.xml
@@ -20,5 +20,6 @@
<item>com.android.cts.verifier.car.CarDockTestActivity</item>
<item>com.android.cts.verifier.deskclock.DeskClockTestsActivity</item>
<item>com.android.cts.verifier.screenpinning.ScreenPinningTestActivity</item>
+ <item>com.android.cts.verifier.notifications.ShortcutThrottlingResetActivity</item>
</string-array>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 9c2992b..e9f29b8 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -891,7 +891,7 @@
<string name="snsr_mag_verify_calibrated_uncalibrated">Verifying the relationship between
calibrated and uncalibrated measurements...</string>
<string name="snsr_mag_calibration_description">Please calibrate the Magnetometer by moving
- it in 8 shapes in different orientations.</string>
+ it in 8 shapes in different orientations. Click \"Next\" to start and click \"Next\" once again to end calibration.</string>
<string name="snsr_mag_calibration_complete">When done, leave the device in a flat surface, far
from all metallic objects (if the test does not pass, try re-running it outdoors).</string>
<string name="snsr_mag_measurement">-> (%1$.2f, %2$.2f, %3$.2f) : %4$.2f uT</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
index cfa097b..5657edd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
@@ -181,6 +181,14 @@
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
+ try {
+ mService.stopRendering();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to execute stopRendering", e);
+ }
+ if (mConnection != null) {
+ unbindService(mConnection);
+ }
mReader.close();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
index 229a9dc..b4aa606 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -170,23 +170,23 @@
Sensor.TYPE_MAGNETIC_FIELD,
SensorManager.SENSOR_DELAY_NORMAL);
+ SensorTestLogger logger = getTestLogger();
+ logger.logInstructions(R.string.snsr_mag_calibration_description);
+ logger.logInstructions(R.string.snsr_mag_calibration_complete);
+ waitForUserToContinue();
+
TestSensorEventListener listener = new TestSensorEventListener(environment) {
@Override
public void onSensorChanged(SensorEvent event) {
clearText();
float values[] = event.values;
- SensorTestLogger logger = getTestLogger();
- logger.logInstructions(R.string.snsr_mag_calibration_description);
logger.logMessage(
R.string.snsr_mag_measurement,
values[0],
values[1],
values[2],
SensorCtsHelper.getMagnitude(values));
-
- // TODO: automate finding out when the magnetometer is calibrated
- logger.logInstructions(R.string.snsr_mag_calibration_complete);
}
};
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ReadDefaultUris.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ReadDefaultUris.java
index 37476f7..70f12d9 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ReadDefaultUris.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ReadDefaultUris.java
@@ -67,6 +67,5 @@
mp.stop();
mp.release();
Thread.sleep(timeToPlayMs);
- assertFalse(mAudioManager.isMusicActive());
}
}
diff --git a/hostsidetests/incident/apps/procstatsapp/Android.mk b/hostsidetests/incident/apps/procstatsapp/Android.mk
new file mode 100644
index 0000000..a02c29d
--- /dev/null
+++ b/hostsidetests/incident/apps/procstatsapp/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsProcStatsProtoApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctstestrunner \
+ compatibility-device-util \
+ android-support-v4
+
+LOCAL_SDK_VERSION := test_current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/incident/apps/procstatsapp/AndroidManifest.xml b/hostsidetests/incident/apps/procstatsapp/AndroidManifest.xml
new file mode 100644
index 0000000..a0cccb4
--- /dev/null
+++ b/hostsidetests/incident/apps/procstatsapp/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.cts.procstats" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name=".SimpleActivity" android:exported="true" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.cts.procstats" />
+</manifest>
diff --git a/hostsidetests/incident/apps/procstatsapp/src/com/android/server/cts/procstats/SimpleActivity.java b/hostsidetests/incident/apps/procstatsapp/src/com/android/server/cts/procstats/SimpleActivity.java
new file mode 100644
index 0000000..69ff75e
--- /dev/null
+++ b/hostsidetests/incident/apps/procstatsapp/src/com/android/server/cts/procstats/SimpleActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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.server.cts.procstats;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.Override;
+
+public class SimpleActivity extends Activity {
+
+ private static final String TAG = "ProcstatsAppRunningTest";
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ Log.i(TAG, "Procstats app is running");
+ }
+}
+
diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
index 57d64bb..386c324 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -15,14 +15,9 @@
*/
package com.android.server.cts;
-import com.android.ddmlib.IShellOutputReceiver;
import com.android.tradefed.log.LogUtil;
-import com.google.common.base.Charsets;
-
import java.util.Random;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Test for "dumpsys batterystats -c
@@ -710,64 +705,6 @@
}
/**
- * Runs logcat and waits (for a maximumum of maxTimeMs) until the desired text is displayed with
- * the given tag.
- * Logcat is not cleared, so make sure that text is unique (won't get false hits from old data).
- * Note that, in practice, the actual max wait time seems to be about 10s longer than maxTimeMs.
- */
- private void checkLogcatForText(String logcatTag, String text, int maxTimeMs) {
- IShellOutputReceiver receiver = new IShellOutputReceiver() {
- private final StringBuilder mOutputBuffer = new StringBuilder();
- private final AtomicBoolean mIsCanceled = new AtomicBoolean(false);
-
- @Override
- public void addOutput(byte[] data, int offset, int length) {
- if (!isCancelled()) {
- synchronized (mOutputBuffer) {
- String s = new String(data, offset, length, Charsets.UTF_8);
- mOutputBuffer.append(s);
- if (checkBufferForText()) {
- mIsCanceled.set(true);
- }
- }
- }
- }
-
- private boolean checkBufferForText() {
- if (mOutputBuffer.indexOf(text) > -1) {
- return true;
- } else {
- // delete all old data (except the last few chars) since they don't contain text
- // (presumably large chunks of data will be added at a time, so this is
- // sufficiently efficient.)
- int newStart = mOutputBuffer.length() - text.length();
- if (newStart > 0) {
- mOutputBuffer.delete(0, newStart);
- }
- return false;
- }
- }
-
- @Override
- public boolean isCancelled() {
- return mIsCanceled.get();
- }
-
- @Override
- public void flush() {
- }
- };
-
- try {
- // Wait for at most maxTimeMs for logcat to display the desired text.
- getDevice().executeShellCommand(String.format("logcat -s %s -e '%s'", logcatTag, text),
- receiver, maxTimeMs, TimeUnit.MILLISECONDS, 0);
- } catch (com.android.tradefed.device.DeviceNotAvailableException e) {
- System.err.println(e);
- }
- }
-
- /**
* Returns the bytes downloaded for the wifi transfer download tests.
* @param requestCode the output of executeForeground() or executeBackground() to identify in
* the logcat the line associated with the desired download information
diff --git a/hostsidetests/incident/src/com/android/server/cts/NetstatsIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/NetstatsIncidentTest.java
index f5c13c2..bdf7dcc 100644
--- a/hostsidetests/incident/src/com/android/server/cts/NetstatsIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/NetstatsIncidentTest.java
@@ -374,16 +374,14 @@
assertNotNegative("TX bytes", bucket.getTxBytes());
assertNotNegative("TX packets", bucket.getTxPackets());
-// 10 was still too big? // It should be safe to say # of bytes >= 10 * 10 of packets, due to headers, etc...
- final long FACTOR = 4;
assertTrue(
String.format("# of bytes %d too small for # of packets %d",
bucket.getRxBytes(), bucket.getRxPackets()),
- bucket.getRxBytes() >= bucket.getRxPackets() * FACTOR);
+ bucket.getRxBytes() >= bucket.getRxPackets());
assertTrue(
String.format("# of bytes %d too small for # of packets %d",
bucket.getTxBytes(), bucket.getTxPackets()),
- bucket.getTxBytes() >= bucket.getTxPackets() * FACTOR);
+ bucket.getTxBytes() >= bucket.getTxPackets());
}
}
diff --git a/hostsidetests/incident/src/com/android/server/cts/ProcStatsProtoTest.java b/hostsidetests/incident/src/com/android/server/cts/ProcStatsProtoTest.java
new file mode 100644
index 0000000..640da22
--- /dev/null
+++ b/hostsidetests/incident/src/com/android/server/cts/ProcStatsProtoTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.server.cts;
+
+import android.service.procstats.ProcessStatsProto;
+import android.service.procstats.ProcessStatsServiceDumpProto;
+
+/**
+ * Test proto dump of procstats
+ *
+ * $ make -j32 CtsIncidentHostTestCases
+ * $ cts-tradefed run cts-dev -m CtsIncidentHostTestCases \
+ * -t com.android.server.cts.ProcStatsProtoTest
+ */
+public class ProcStatsProtoTest extends ProtoDumpTestCase {
+
+ private static final String DEVICE_SIDE_TEST_APK = "CtsProcStatsProtoApp.apk";
+ private static final String DEVICE_SIDE_TEST_PACKAGE = "com.android.server.cts.procstats";
+ private static final String TEST_APP_TAG = "ProcstatsAppRunningTest";
+ private static final String TEST_APP_LOG = "Procstats app is running";
+ private static final int WAIT_MS = 1000;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ getDevice().executeShellCommand("dumpsys procstats --clear");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE);
+ super.tearDown();
+ }
+
+ /**
+ * Test that procstats dump is reasonable, it installs procstats app and
+ * starts the activity, then asserts the procstats dump contains the package.
+ *
+ * @throws Exception
+ */
+ public void testDump() throws Exception {
+ installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true);
+ int retries = 3;
+ do {
+ getDevice().executeShellCommand(
+ "am start -n com.android.server.cts.procstats/.SimpleActivity");
+ } while (!checkLogcatForText(TEST_APP_TAG, TEST_APP_LOG, WAIT_MS) && retries-- > 0);
+
+ final ProcessStatsServiceDumpProto dump = getDump(ProcessStatsServiceDumpProto.parser(),
+ "dumpsys procstats --proto");
+
+ int N = dump.getProcstatsNow().getProcessStatsCount();
+ boolean containsTestApp = false;
+ for (int i = 0; i < N; i++) {
+ ProcessStatsProto ps = dump.getProcstatsNow().getProcessStats(i);
+ if (DEVICE_SIDE_TEST_PACKAGE.equals(ps.getProcess())) {
+ containsTestApp = true;
+ }
+ }
+
+ assertTrue(N > 0);
+ assertTrue(containsTestApp); // found test app in procstats dump
+ }
+}
diff --git a/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java b/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
index 5739bf4..d273033 100644
--- a/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
+++ b/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
@@ -17,6 +17,7 @@
package com.android.server.cts;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestResult;
@@ -31,11 +32,14 @@
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
+import com.google.common.base.Charsets;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageLite;
import com.google.protobuf.Parser;
import java.io.FileNotFoundException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -176,4 +180,66 @@
assertTrue("No group found for pattern '" + pattern + "'", matcher.groupCount() > 0);
return matcher.group(1);
}
+
+ /**
+ * Runs logcat and waits (for a maximumum of maxTimeMs) until the desired text is displayed with
+ * the given tag.
+ * Logcat is not cleared, so make sure that text is unique (won't get false hits from old data).
+ * Note that, in practice, the actual max wait time seems to be about 10s longer than maxTimeMs.
+ * Returns true means the desired log line is found.
+ */
+ protected boolean checkLogcatForText(String logcatTag, String text, int maxTimeMs) {
+ IShellOutputReceiver receiver = new IShellOutputReceiver() {
+ private final StringBuilder mOutputBuffer = new StringBuilder();
+ private final AtomicBoolean mIsCanceled = new AtomicBoolean(false);
+
+ @Override
+ public void addOutput(byte[] data, int offset, int length) {
+ if (!isCancelled()) {
+ synchronized (mOutputBuffer) {
+ String s = new String(data, offset, length, Charsets.UTF_8);
+ mOutputBuffer.append(s);
+ if (checkBufferForText()) {
+ mIsCanceled.set(true);
+ }
+ }
+ }
+ }
+
+ private boolean checkBufferForText() {
+ if (mOutputBuffer.indexOf(text) > -1) {
+ return true;
+ } else {
+ // delete all old data (except the last few chars) since they don't contain text
+ // (presumably large chunks of data will be added at a time, so this is
+ // sufficiently efficient.)
+ int newStart = mOutputBuffer.length() - text.length();
+ if (newStart > 0) {
+ mOutputBuffer.delete(0, newStart);
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return mIsCanceled.get();
+ }
+
+ @Override
+ public void flush() {
+ }
+ };
+
+ try {
+ // Wait for at most maxTimeMs for logcat to display the desired text.
+ getDevice().executeShellCommand(String.format("logcat -s %s -e '%s'", logcatTag, text),
+ receiver, maxTimeMs, TimeUnit.MILLISECONDS, 0);
+ return receiver.isCancelled();
+ } catch (com.android.tradefed.device.DeviceNotAvailableException e) {
+ System.err.println(e);
+ }
+ return false;
+ }
+
}
diff --git a/hostsidetests/incident/src/com/android/server/cts/StatsdValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/StatsdValidationTest.java
index c534b71..c147265 100644
--- a/hostsidetests/incident/src/com/android/server/cts/StatsdValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/StatsdValidationTest.java
@@ -29,21 +29,20 @@
import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
import com.android.internal.os.StatsdConfigProto.SimplePredicate;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.internal.os.StatsdConfigProto.ValueMetric;
import com.android.os.AtomsProto.Atom;
import com.android.os.AtomsProto.KernelWakelockPulled;
import com.android.os.AtomsProto.ScreenStateChanged;
import com.android.os.StatsLog.ConfigMetricsReport;
import com.android.os.StatsLog.ConfigMetricsReportList;
import com.android.tradefed.log.LogUtil;
-import com.google.common.base.Charsets;
+
import com.google.common.io.Files;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Test for statsd
@@ -55,6 +54,8 @@
private static final String TAG = "StatsdValidationTest";
private static final boolean TESTS_ENABLED = false;
+ // For tests that require incidentd. Keep as true until TESTS_ENABLED is permanently enabled.
+ private static final boolean INCIDENTD_TESTS_ENABLED = true;
// TODO: Use a statsd-specific app (temporarily just borrowing the batterystats app)
private static final String DEVICE_SIDE_TEST_APK = "CtsStatsDApp.apk";
@@ -170,6 +171,7 @@
// Also tests that anomaly detection works when spanning multiple buckets.
public void testCountAnomalyDetection() throws Exception {
if (!TESTS_ENABLED) return;
+ if (!INCIDENTD_TESTS_ENABLED) return;
// TODO: Don't use screen-state as the atom.
StatsdConfig config = getDefaultConfig()
.addCountMetric(CountMetric.newBuilder()
@@ -214,6 +216,7 @@
// Also tests that refractory periods in anomaly detection work.
public void testDurationAnomalyDetection() throws Exception {
if (!TESTS_ENABLED) return;
+ if (!INCIDENTD_TESTS_ENABLED) return;
// TODO: Do NOT use screenState for this, since screens auto-turn-off after a variable time.
StatsdConfig config = getDefaultConfig()
.addDurationMetric(DurationMetric.newBuilder()
@@ -222,14 +225,6 @@
.setAggregationType(DurationMetric.AggregationType.SUM)
.setBucket(Bucket.newBuilder().setBucketSizeMillis(5_000))
)
- .addPredicate(Predicate.newBuilder()
- .setName("SCREEN_IS_ON")
- .setSimplePredicate(SimplePredicate.newBuilder()
- .setStart("SCREEN_TURNED_ON")
- .setStop("SCREEN_TURNED_OFF")
- .setCountNesting(false)
- )
- )
.addAlert(Alert.newBuilder()
.setName("testDurationAnomalyDetectionAlert")
.setMetricName("METRIC")
@@ -274,6 +269,81 @@
assertTrue(didIncidentdFireSince(markDeviceDate));
}
+ // TODO: There is no value anomaly detection code yet! So this will fail.
+ // Tests that anomaly detection for value works.
+ public void testValueAnomalyDetection() throws Exception {
+ if (!TESTS_ENABLED) return;
+ if (!INCIDENTD_TESTS_ENABLED) return;
+ // TODO: Definitely don't use screen-state as the atom. This MUST be changed.
+ StatsdConfig config = getDefaultConfig()
+ .addValueMetric(ValueMetric.newBuilder()
+ .setName("METRIC")
+ .setWhat("SCREEN_TURNED_ON")
+ .setValueField(ScreenStateChanged.DISPLAY_STATE_FIELD_NUMBER)
+ .setBucket(Bucket.newBuilder().setBucketSizeMillis(5_000))
+ )
+ .addAlert(Alert.newBuilder()
+ .setName("testValueAnomalyDetectionAlert")
+ .setMetricName("METRIC")
+ .setNumberOfBuckets(4)
+ .setRefractoryPeriodSecs(20)
+ .setTriggerIfSumGt(ScreenStateChanged.State.STATE_OFF.getNumber())
+ .setIncidentdDetails(Alert.IncidentdDetails.newBuilder()
+ .addSection(-1)
+ )
+ )
+ .build();
+ uploadConfig(config);
+
+ turnScreenOff();
+ String markDeviceDate = getCurrentLogcatDate();
+ turnScreenOff(); // value = STATE_OFF = 1 (probably)
+ Thread.sleep(2000);
+ assertFalse(didIncidentdFireSince(markDeviceDate));
+ turnScreenOn(); // value = STATE_ON = 2 (probably)
+ Thread.sleep(2000);
+ assertTrue(didIncidentdFireSince(markDeviceDate));
+
+ turnScreenOff();
+ }
+
+ // Tests that anomaly detection for gauge works.
+ public void testGaugeAnomalyDetection() throws Exception {
+ if (!TESTS_ENABLED) return;
+ if (!INCIDENTD_TESTS_ENABLED) return;
+ // TODO: Definitely don't use screen-state as the atom. This MUST be changed.
+ StatsdConfig config = getDefaultConfig()
+ .addGaugeMetric(GaugeMetric.newBuilder()
+ .setName("METRIC")
+ .setWhat("SCREEN_TURNED_ON")
+ .setGaugeField(ScreenStateChanged.DISPLAY_STATE_FIELD_NUMBER)
+ .setBucket(Bucket.newBuilder().setBucketSizeMillis(10_000))
+ )
+ .addAlert(Alert.newBuilder()
+ .setName("testGaugeAnomalyDetectionAlert")
+ .setMetricName("METRIC")
+ .setNumberOfBuckets(1)
+ .setRefractoryPeriodSecs(20)
+ .setTriggerIfSumGt(ScreenStateChanged.State.STATE_OFF.getNumber())
+ .setIncidentdDetails(Alert.IncidentdDetails.newBuilder()
+ .addSection(-1)
+ )
+ )
+ .build();
+ uploadConfig(config);
+
+ turnScreenOff();
+ String markDeviceDate = getCurrentLogcatDate();
+ turnScreenOff(); // gauge = STATE_OFF = 1 (probably)
+ Thread.sleep(2000);
+ assertFalse(didIncidentdFireSince(markDeviceDate));
+ turnScreenOn(); // gauge = STATE_ON = 2 (probably)
+ Thread.sleep(2000);
+ assertTrue(didIncidentdFireSince(markDeviceDate));
+
+ turnScreenOff();
+ }
+
/**
* Determines whether logcat indicates that incidentd fired since the given device date.
*/
@@ -288,7 +358,6 @@
}
private void uploadConfig(StatsdConfig config) throws Exception {
- LogUtil.CLog.d("uploading the config:\n" + config.toString());
File configFile = File.createTempFile("statsdconfig", ".config");
Files.write(config.toByteArray(), configFile);
String remotePath = "/data/" + configFile.getName();
@@ -370,64 +439,62 @@
private StatsdConfig.Builder getDefaultConfig() {
StatsdConfig.Builder configBuilder = StatsdConfig.newBuilder();
configBuilder.setName("12345");
- configBuilder.addAtomMatcher(
- AtomMatcher.newBuilder()
- .setName("SCREEN_TURNED_ON")
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setTag(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
- .addKeyValueMatcher(KeyValueMatcher.newBuilder()
- .setKeyMatcher(
- KeyMatcher.newBuilder()
- .setKey(ScreenStateChanged
- .DISPLAY_STATE_FIELD_NUMBER)
- ).setEqInt(
- ScreenStateChanged.State.STATE_ON_VALUE))));
- configBuilder.addAtomMatcher(
- AtomMatcher.newBuilder()
- .setName("SCREEN_TURNED_OFF")
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setTag(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
- .addKeyValueMatcher(KeyValueMatcher.newBuilder()
- .setKeyMatcher(
- KeyMatcher.newBuilder()
- .setKey(ScreenStateChanged
- .DISPLAY_STATE_FIELD_NUMBER)
- ).setEqInt(
- ScreenStateChanged.State.STATE_OFF_VALUE)
- )));
- configBuilder.addAtomMatcher(
- AtomMatcher.newBuilder()
- .setName("UID_PROCESS_STATE_CHANGED")
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setTag(Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER)));
- // up to 110 is fine. 128 not good
- configBuilder.addAtomMatcher(
- AtomMatcher.newBuilder()
- .setName("KERNEL_WAKELOCK_PULLED")
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setTag(Atom.KERNEL_WAKELOCK_PULLED_FIELD_NUMBER)));
- configBuilder.addAtomMatcher(
- AtomMatcher.newBuilder()
- .setName("CPU_TIME_PER_UID_PULLED")
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setTag(Atom.CPU_TIME_PER_UID_PULLED_FIELD_NUMBER)));
- configBuilder.addAtomMatcher(
- AtomMatcher.newBuilder()
- .setName("CPU_TIME_PER_FREQ_PULLED")
- .setSimpleAtomMatcher(
- SimpleAtomMatcher.newBuilder()
- .setTag(Atom.CPU_TIME_PER_FREQ_PULLED_FIELD_NUMBER)));
- configBuilder.addPredicate(Predicate.newBuilder()
+ configBuilder
+ .addAtomMatcher(AtomMatcher.newBuilder()
+ .setName("SCREEN_TURNED_ON")
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setTag(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
+ .addKeyValueMatcher(KeyValueMatcher.newBuilder()
+ .setKeyMatcher(KeyMatcher.newBuilder()
+ .setKey(ScreenStateChanged.DISPLAY_STATE_FIELD_NUMBER)
+ )
+ .setEqInt(ScreenStateChanged.State.STATE_ON_VALUE)
+ )
+ )
+ )
+ .addAtomMatcher(AtomMatcher.newBuilder()
+ .setName("SCREEN_TURNED_OFF")
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setTag(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
+ .addKeyValueMatcher(KeyValueMatcher.newBuilder()
+ .setKeyMatcher(KeyMatcher.newBuilder()
+ .setKey(ScreenStateChanged.DISPLAY_STATE_FIELD_NUMBER)
+ )
+ .setEqInt(ScreenStateChanged.State.STATE_OFF_VALUE)
+ )
+ )
+ )
+ .addAtomMatcher(AtomMatcher.newBuilder()
+ .setName("UID_PROCESS_STATE_CHANGED")
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setTag(Atom.UID_PROCESS_STATE_CHANGED_FIELD_NUMBER)
+ )
+ )
+ .addAtomMatcher(AtomMatcher.newBuilder()
+ .setName("KERNEL_WAKELOCK_PULLED")
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setTag(Atom.KERNEL_WAKELOCK_PULLED_FIELD_NUMBER)
+ )
+ )
+ .addAtomMatcher(AtomMatcher.newBuilder()
+ .setName("CPU_TIME_PER_UID_PULLED")
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setTag(Atom.CPU_TIME_PER_UID_PULLED_FIELD_NUMBER))
+ )
+ .addAtomMatcher(AtomMatcher.newBuilder()
+ .setName("CPU_TIME_PER_FREQ_PULLED")
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
+ .setTag(Atom.CPU_TIME_PER_FREQ_PULLED_FIELD_NUMBER))
+ )
+ .addPredicate(Predicate.newBuilder()
.setName("SCREEN_IS_ON")
.setSimplePredicate(SimplePredicate.newBuilder()
- .setStart("SCREEN_TURNED_ON")
- .setStop("SCREEN_TURNED_OFF")
- .setCountNesting(false)));
+ .setStart("SCREEN_TURNED_ON")
+ .setStop("SCREEN_TURNED_OFF")
+ .setCountNesting(false)
+ )
+ )
+ ;
return configBuilder;
}
@@ -590,64 +657,6 @@
}
/**
- * Runs logcat and waits (for a maximumum of maxTimeMs) until the desired text is displayed with
- * the given tag.
- * Logcat is not cleared, so make sure that text is unique (won't get false hits from old data).
- * Note that, in practice, the actual max wait time seems to be about 10s longer than maxTimeMs.
- */
- private void checkLogcatForText(String logcatTag, String text, int maxTimeMs) {
- IShellOutputReceiver receiver = new IShellOutputReceiver() {
- private final StringBuilder mOutputBuffer = new StringBuilder();
- private final AtomicBoolean mIsCanceled = new AtomicBoolean(false);
-
- @Override
- public void addOutput(byte[] data, int offset, int length) {
- if (!isCancelled()) {
- synchronized (mOutputBuffer) {
- String s = new String(data, offset, length, Charsets.UTF_8);
- mOutputBuffer.append(s);
- if (checkBufferForText()) {
- mIsCanceled.set(true);
- }
- }
- }
- }
-
- private boolean checkBufferForText() {
- if (mOutputBuffer.indexOf(text) > -1) {
- return true;
- } else {
- // delete all old data (except the last few chars) since they don't contain text
- // (presumably large chunks of data will be added at a time, so this is
- // sufficiently efficient.)
- int newStart = mOutputBuffer.length() - text.length();
- if (newStart > 0) {
- mOutputBuffer.delete(0, newStart);
- }
- return false;
- }
- }
-
- @Override
- public boolean isCancelled() {
- return mIsCanceled.get();
- }
-
- @Override
- public void flush() {
- }
- };
-
- try {
- // Wait for at most maxTimeMs for logcat to display the desired text.
- getDevice().executeShellCommand(String.format("logcat -s %s -e '%s'", logcatTag, text),
- receiver, maxTimeMs, TimeUnit.MILLISECONDS, 0);
- } catch (com.android.tradefed.device.DeviceNotAvailableException e) {
- System.err.println(e);
- }
- }
-
- /**
* Determines if the device has the given feature.
* Prints a warning if its value differs from requiredAnswer.
*/
diff --git a/hostsidetests/inputmethodservice/hostside/Android.mk b/hostsidetests/inputmethodservice/hostside/Android.mk
index 19aae73..5ff22a2 100644
--- a/hostsidetests/inputmethodservice/hostside/Android.mk
+++ b/hostsidetests/inputmethodservice/hostside/Android.mk
@@ -30,7 +30,6 @@
cts-tradefed \
tradefed
LOCAL_STATIC_JAVA_LIBRARIES := \
- cts-inputmethodservice-common-host \
- hamcrest-library
+ cts-inputmethodservice-common-host
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
index b094812..bc906a0 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
@@ -22,11 +22,10 @@
import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_COMPONENT;
import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.TEST_START;
-import static org.hamcrest.Matchers.emptyOrNullString;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -91,7 +90,8 @@
// There should be a new IME that is different from the IME1
final String newIme = shell(ShellCommandUtils.getCurrentIme());
- assertThat(newIme, is(not(emptyOrNullString())));
+ assertNotNull(newIme);
+ assertFalse(newIme.isEmpty());
assertNotEquals(newIme, Ime1Constants.IME_ID);
}
@@ -107,7 +107,8 @@
// There should be a new IME that is different from the IME1
final String newIme = shell(ShellCommandUtils.getCurrentIme());
- assertThat(newIme, is(not(emptyOrNullString())));
+ assertNotNull(newIme);
+ assertFalse(newIme.isEmpty());
assertNotEquals(newIme, Ime1Constants.IME_ID);
}
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 4548fb0..6093384 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -104,6 +104,8 @@
<service android:name="android.app.stubs.MockService" />
+ <service android:name="android.app.stubs.NullService" />
+
<activity android:name="android.app.stubs.SearchManagerStubActivity"
android:label="SearchManagerStubActivity">
<intent-filter>
diff --git a/tests/app/app/src/android/app/stubs/ActionBarActivity.java b/tests/app/app/src/android/app/stubs/ActionBarActivity.java
index 5e15407..c9d38b5 100644
--- a/tests/app/app/src/android/app/stubs/ActionBarActivity.java
+++ b/tests/app/app/src/android/app/stubs/ActionBarActivity.java
@@ -20,7 +20,11 @@
import android.os.Bundle;
import android.view.Menu;
+import java.util.concurrent.CountDownLatch;
+
public class ActionBarActivity extends Activity {
+ // Make sure that ActionBarActivity has focus before running Action Bar Tests.
+ public CountDownLatch windowFocusSignal;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -29,6 +33,7 @@
if (bar != null) {
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
+ windowFocusSignal = new CountDownLatch(1);
}
@Override
@@ -36,4 +41,12 @@
getMenuInflater().inflate(R.menu.flat_menu, menu);
return true;
}
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (hasFocus) {
+ windowFocusSignal.countDown();
+ }
+ }
}
diff --git a/tests/app/app/src/android/app/stubs/NullService.java b/tests/app/app/src/android/app/stubs/NullService.java
new file mode 100644
index 0000000..6a1c618
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/NullService.java
@@ -0,0 +1,36 @@
+/*
+ * 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.app.stubs;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * A Service that always returns null from onBind(Intent).
+ */
+public class NullService extends Service {
+ private static final String TAG = "NullService";
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.i(TAG, "onBind() returning null");
+ return null;
+ }
+
+}
diff --git a/tests/app/src/android/app/cts/ActionBarTest.java b/tests/app/src/android/app/cts/ActionBarTest.java
index 8bfaa59..2cfc970 100644
--- a/tests/app/src/android/app/cts/ActionBarTest.java
+++ b/tests/app/src/android/app/cts/ActionBarTest.java
@@ -25,6 +25,8 @@
import android.view.KeyEvent;
import android.view.Window;
+import java.util.concurrent.TimeUnit;
+
public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarActivity> {
private ActionBarActivity mActivity;
@@ -83,13 +85,16 @@
assertEquals(t3, mBar.getTabAt(4));
}
- public void testOptionsMenuKey() {
+ public void testOptionsMenuKey() throws Exception {
if (!mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
return;
}
final boolean menuIsVisible[] = {false};
mActivity.getActionBar().addOnMenuVisibilityListener(
isVisible -> menuIsVisible[0] = isVisible);
+ // Wait here for test activity to gain focus before sending keyevent.
+ // Visibility listener needs the action bar to be visible.
+ assertTrue(mActivity.windowFocusSignal.await(1000, TimeUnit.MILLISECONDS));
getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
getInstrumentation().waitForIdleSync();
assertTrue(menuIsVisible[0]);
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 5f8202d..d660040 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -26,6 +26,7 @@
import android.app.stubs.LocalForegroundService;
import android.app.stubs.LocalGrantedService;
import android.app.stubs.LocalService;
+import android.app.stubs.NullService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -36,6 +37,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
@@ -85,6 +87,41 @@
}
}
+ private static class NullServiceConnection implements ServiceConnection {
+ boolean mNullBinding = false;
+
+ @Override public void onServiceConnected(ComponentName name, IBinder service) {}
+ @Override public void onServiceDisconnected(ComponentName name) {}
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ synchronized (this) {
+ mNullBinding = true;
+ this.notifyAll();
+ }
+ }
+
+ public void waitForNullBinding(final long timeout) {
+ long now = SystemClock.uptimeMillis();
+ final long end = now + timeout;
+ synchronized (this) {
+ while (!mNullBinding && (now < end)) {
+ try {
+ this.wait(end - now);
+ } catch (InterruptedException e) {
+ }
+ now = SystemClock.uptimeMillis();
+ }
+ }
+ }
+
+ public boolean nullBindingReceived() {
+ synchronized (this) {
+ return mNullBinding;
+ }
+ }
+ }
+
private class TestConnection implements ServiceConnection {
private final boolean mExpectDisconnect;
private final boolean mSetReporter;
@@ -831,4 +868,28 @@
// expected
}
}
+
+ /**
+ * Verify that when the requested service's onBind() returns null,
+ * the connection's onNullBinding() method is invoked.
+ */
+ @MediumTest
+ public void testNullServiceBinder() throws Exception {
+ Intent intent = new Intent(mContext, NullService.class);
+ intent.setAction("testNullServiceBinder");
+ NullServiceConnection conn1 = new NullServiceConnection();
+ NullServiceConnection conn2 = new NullServiceConnection();
+ try {
+ assertTrue(mContext.bindService(intent, conn1, Context.BIND_AUTO_CREATE));
+ conn1.waitForNullBinding(DELAY);
+ assertTrue(conn1.nullBindingReceived());
+
+ assertTrue(mContext.bindService(intent, conn2, Context.BIND_AUTO_CREATE));
+ conn2.waitForNullBinding(DELAY);
+ assertTrue(conn2.nullBindingReceived());
+ } finally {
+ mContext.unbindService(conn1);
+ mContext.unbindService(conn2);
+ }
+ }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationScorerTest.java b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationScorerTest.java
new file mode 100644
index 0000000..8569472
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationScorerTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.service.autofill.FieldsClassificationScorer;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.autofill.AutofillValue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class FieldsClassificationScorerTest {
+
+ @Test
+ public void testGetScore_nullValue() {
+ assertThat(FieldsClassificationScorer.getScore(null, "D'OH!")).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetScore_nonTextValue() {
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forToggle(true), "D'OH!"))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void testGetScore_nullUserData() {
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("D'OH!"), null))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void testGetScore_fullMatch() {
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("d'oh!"), "d'oh!"))
+ .isEqualTo(100_0000);
+ }
+
+ @Test
+ public void testGetScore_fullMatchMixedCase() {
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("D'OH!"), "D'oH!"))
+ .isEqualTo(100_0000);
+ }
+
+ // TODO(b/67867469): might need to change it once it supports different sizes
+ @Test
+ public void testGetScore_mismatchDifferentSizes() {
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("One"), "MoreThanOne"))
+ .isEqualTo(0);
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("MoreThanOne"), "One"))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void testGetScore_partialMatch() {
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("Dude"), "Dxxx"))
+ .isEqualTo(25_0000);
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("Dude"), "DUxx"))
+ .isEqualTo(50_0000);
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("Dude"), "DUDx"))
+ .isEqualTo(75_0000);
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("Dxxx"), "Dude"))
+ .isEqualTo(25_0000);
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("DUxx"), "Dude"))
+ .isEqualTo(50_0000);
+ assertThat(FieldsClassificationScorer.getScore(AutofillValue.forText("DUDx"), "Dude"))
+ .isEqualTo(75_0000);
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
index 59e7115..e78f85c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
@@ -16,7 +16,7 @@
package android.autofillservice.cts;
import static android.autofillservice.cts.Helper.assertFillEventForContextCommitted;
-import static android.autofillservice.cts.Helper.assertFillEventForFieldsDetected;
+import static android.autofillservice.cts.Helper.assertFillEventForFieldsClassification;
import static android.autofillservice.cts.Helper.runShellCommand;
import static android.service.autofill.FillResponse.FLAG_TRACK_CONTEXT_COMMITED;
@@ -82,7 +82,7 @@
}
@Test
- public void testFullHit() throws Exception {
+ public void testHit_oneUserData_oneDetectableField() throws Exception {
// Set service.
enableService();
@@ -105,7 +105,6 @@
callback.assertUiUnavailableEvent(field);
// Simulate user input
- mActivity.focusCell(1, 1);
mActivity.setText(1, 1, "fully");
// Finish context.
@@ -116,7 +115,157 @@
InstrumentedAutoFillService.peekInstance().getFillEventHistory();
final List<Event> events = history.getEvents();
assertWithMessage("Wrong number of events: %s", events).that(events.size()).isEqualTo(1);
- assertFillEventForFieldsDetected(events.get(0), "myId", 0);
+ assertFillEventForFieldsClassification(events.get(0), fieldId, "myId", 1000000);
+ }
+
+ @Test
+ public void testHit_manyUserData_oneDetectableField_bestMatchIsFirst() throws Exception {
+ manyUserData_oneDetectableField(true);
+ }
+
+ @Test
+ public void testHit_manyUserData_oneDetectableField_bestMatchIsSecond() throws Exception {
+ manyUserData_oneDetectableField(false);
+ }
+
+ private void manyUserData_oneDetectableField(boolean firstMatch) throws Exception {
+ // Set service.
+ enableService();
+
+ // Set expectations.
+ final String expectedId;
+ final String typedText;
+ if (firstMatch) {
+ expectedId = "1stId";
+ typedText = "IAM111";
+ } else {
+ expectedId = "2ndId";
+ typedText = "IAM222";
+ }
+ mActivity.getAutofillManager().setUserData(new UserData.Builder("1stId", "Iam1ST")
+ .add("2ndId", "Iam2ND").build());
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ final EditText field = mActivity.getCell(1, 1);
+ final AutofillId fieldId = field.getAutofillId();
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setFillResponseFlags(FLAG_TRACK_CONTEXT_COMMITED)
+ .setFieldClassificationIds(fieldId)
+ .build());
+
+ // Trigger autofill
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ sUiBot.assertNoDatasets();
+ callback.assertUiUnavailableEvent(field);
+
+ // Simulate user input
+ mActivity.setText(1, 1, typedText);
+
+ // Finish context.
+ mActivity.getAutofillManager().commit();
+
+ // Assert results
+ final FillEventHistory history =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ final List<Event> events = history.getEvents();
+ assertWithMessage("Wrong number of events: %s", events).that(events.size()).isEqualTo(1);
+ // Matches 4 of 6 chars - 66.6666%
+ assertFillEventForFieldsClassification(events.get(0), fieldId, expectedId, 666666);
+ }
+
+ @Test
+ public void testHit_oneUserData_manyDetectableFields() throws Exception {
+ // Set service.
+ enableService();
+
+ // Set expectations.
+ mActivity.getAutofillManager()
+ .setUserData(new UserData.Builder("myId", "FULLY").build());
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ final EditText field1 = mActivity.getCell(1, 1);
+ final AutofillId fieldId1 = field1.getAutofillId();
+ final EditText field2 = mActivity.getCell(1, 2);
+ final AutofillId fieldId2 = field2.getAutofillId();
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setFillResponseFlags(FLAG_TRACK_CONTEXT_COMMITED)
+ .setFieldClassificationIds(fieldId1, fieldId2)
+ .build());
+
+ // Trigger autofill
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ sUiBot.assertNoDatasets();
+ callback.assertUiUnavailableEvent(field1);
+
+ // Simulate user input
+ mActivity.setText(1, 1, "fully"); // 100%
+ mActivity.setText(1, 2, "fooly"); // 60%
+
+ // Finish context.
+ mActivity.getAutofillManager().commit();
+
+ // Assert results
+ final FillEventHistory history =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ final List<Event> events = history.getEvents();
+ assertWithMessage("Wrong number of events: %s", events).that(events.size()).isEqualTo(1);
+ assertFillEventForFieldsClassification(events.get(0),
+ new AutofillId[] { fieldId1, fieldId2 },
+ new String[] { "myId", "myId" },
+ new int[] { 1000000, 600000 });
+ }
+
+ @Test
+ public void testHit_manyUserData_manyDetectableFields() throws Exception {
+ // Set service.
+ enableService();
+
+ // Set expectations.
+ mActivity.getAutofillManager()
+ .setUserData(new UserData.Builder("myId", "FULLY")
+ .add("otherId", "EMPTY")
+ .build());
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ final EditText field1 = mActivity.getCell(1, 1);
+ final AutofillId fieldId1 = field1.getAutofillId();
+ final EditText field2 = mActivity.getCell(1, 2);
+ final AutofillId fieldId2 = field2.getAutofillId();
+ final EditText field3 = mActivity.getCell(2, 1);
+ final AutofillId fieldId3 = field3.getAutofillId();
+ final EditText field4 = mActivity.getCell(2, 2);
+ final AutofillId fieldId4 = field4.getAutofillId();
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setFillResponseFlags(FLAG_TRACK_CONTEXT_COMMITED)
+ .setFieldClassificationIds(fieldId1, fieldId2)
+ .build());
+
+ // Trigger autofill
+ mActivity.focusCell(1, 1);
+ sReplier.getNextFillRequest();
+
+ sUiBot.assertNoDatasets();
+ callback.assertUiUnavailableEvent(field1);
+
+ // Simulate user input
+ mActivity.setText(1, 1, "fully"); // 100%
+ mActivity.setText(1, 2, "empty"); // 100%
+ mActivity.setText(2, 1, "fooly"); // 60%
+ mActivity.setText(2, 2, "emppy"); // 80%
+
+ // Finish context.
+ mActivity.getAutofillManager().commit();
+
+ // Assert results
+ final FillEventHistory history =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ final List<Event> events = history.getEvents();
+ assertWithMessage("Wrong number of events: %s", events).that(events.size()).isEqualTo(1);
+ assertFillEventForFieldsClassification(events.get(0),
+ new AutofillId[] { fieldId1, fieldId2, fieldId3, fieldId4 },
+ new String[] { "myId", "otherId", "myId", "otherId" },
+ new int[] { 1000000, 1000000, 600000, 800000});
}
@Test
@@ -196,9 +345,9 @@
* - Multipartition (for example, one response with FieldsDetection, others with datasets,
* saveinfo, and/or ignoredIds)
* - make sure detectable fields don't trigger a new partition
- * - test partial hit (for example, 'fool' instead of 'full'
- * - multiple fields
- * - multiple value
+ * v test partial hit (for example, 'fool' instead of 'full'
+ * v multiple fields
+ * v multiple value
* - combinations of above items
*/
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index c95e74e..008e10c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -36,6 +36,8 @@
import android.content.pm.PackageManager;
import android.icu.util.Calendar;
import android.os.Bundle;
+import android.service.autofill.FieldClassification;
+import android.service.autofill.FieldClassification.Match;
import android.service.autofill.FillContext;
import android.service.autofill.FillEventHistory;
import android.support.annotation.NonNull;
@@ -55,6 +57,7 @@
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.function.Function;
/**
@@ -1047,7 +1050,8 @@
private static void assertFillEvent(@NonNull FillEventHistory.Event event,
int eventType, @Nullable String datasetId,
@Nullable String key, @Nullable String value,
- @Nullable String detectedRemoteId, int detectedScore) {
+ @Nullable AutofillId[] detectedAutofillIds, @Nullable String[] detectedRemoteIds,
+ @Nullable int[] detectedScores) {
assertThat(event).isNotNull();
assertWithMessage("Wrong type for %s", event).that(event.getType()).isEqualTo(eventType);
if (datasetId == null) {
@@ -1072,11 +1076,22 @@
.that(event.getChangedFields()).isEmpty();
assertWithMessage("Event '%s' should not have manually-entered fields", event)
.that(event.getManuallyEnteredField()).isEmpty();
- final Map<String, Integer> detectedFields = event.getFieldsClassification();
- if (detectedRemoteId == null) {
+ final Map<AutofillId, FieldClassification> detectedFields = event.getFieldsClassification();
+ if (detectedAutofillIds == null) {
assertThat(detectedFields).isEmpty();
} else {
- assertThat(detectedFields).containsExactly(detectedRemoteId, detectedScore);
+ assertThat(detectedFields).hasSize(detectedAutofillIds.length);
+ int i = 0;
+ for (Entry<AutofillId, FieldClassification> entry : detectedFields.entrySet()) {
+ assertWithMessage("Wrong field id at %s", i).that(entry.getKey())
+ .isEqualTo(detectedAutofillIds[i]);
+ final Match topMatch = entry.getValue().getTopMatch();
+ assertWithMessage("Wrong remote id at %s", i).that(topMatch.getRemoteId())
+ .isEqualTo(detectedRemoteIds[i]);
+ assertWithMessage("Wrong score at %s", i).that(topMatch.getScore())
+ .isEqualTo(detectedScores[i]);
+ i++;
+ }
}
}
@@ -1089,7 +1104,7 @@
*/
public static void assertFillEventForDatasetSelected(@NonNull FillEventHistory.Event event,
@Nullable String datasetId) {
- assertFillEvent(event, TYPE_DATASET_SELECTED, datasetId, null, null, null, -1);
+ assertFillEvent(event, TYPE_DATASET_SELECTED, datasetId, null, null, null, null, null);
}
/**
@@ -1103,7 +1118,7 @@
*/
public static void assertFillEventForDatasetSelected(@NonNull FillEventHistory.Event event,
@Nullable String datasetId, @Nullable String key, @Nullable String value) {
- assertFillEvent(event, TYPE_DATASET_SELECTED, datasetId, key, value, null, -1);
+ assertFillEvent(event, TYPE_DATASET_SELECTED, datasetId, key, value, null, null, null);
}
/**
@@ -1117,7 +1132,7 @@
*/
public static void assertFillEventForSaveShown(@NonNull FillEventHistory.Event event,
@NonNull String datasetId, @NonNull String key, @NonNull String value) {
- assertFillEvent(event, TYPE_SAVE_SHOWN, datasetId, key, value, null, -1);
+ assertFillEvent(event, TYPE_SAVE_SHOWN, datasetId, key, value, null, null, null);
}
/**
@@ -1129,7 +1144,7 @@
*/
public static void assertFillEventForSaveShown(@NonNull FillEventHistory.Event event,
@NonNull String datasetId) {
- assertFillEvent(event, TYPE_SAVE_SHOWN, datasetId, null, null, null, -1);
+ assertFillEvent(event, TYPE_SAVE_SHOWN, datasetId, null, null, null, null, null);
}
/**
@@ -1146,7 +1161,7 @@
@NonNull FillEventHistory.Event event,
@Nullable String datasetId, @NonNull String key, @NonNull String value) {
assertFillEvent(event, TYPE_DATASET_AUTHENTICATION_SELECTED, datasetId, key, value, null,
- -1);
+ null, null);
}
/**
@@ -1161,18 +1176,27 @@
public static void assertFillEventForAuthenticationSelected(
@NonNull FillEventHistory.Event event,
@Nullable String datasetId, @NonNull String key, @NonNull String value) {
- assertFillEvent(event, TYPE_AUTHENTICATION_SELECTED, datasetId, key, value, null, -1);
+ assertFillEvent(event, TYPE_AUTHENTICATION_SELECTED, datasetId, key, value, null, null,
+ null);
}
// TODO(b/67867469): document
- public static void assertFillEventForFieldsDetected(@NonNull FillEventHistory.Event event,
- @NonNull String remoteId, int result) {
- assertFillEvent(event, TYPE_CONTEXT_COMMITTED, null, null, null, remoteId, result);
+ public static void assertFillEventForFieldsClassification(@NonNull FillEventHistory.Event event,
+ @NonNull AutofillId fieldId, @NonNull String remoteId, int score) {
+ assertFillEvent(event, TYPE_CONTEXT_COMMITTED, null, null, null,
+ new AutofillId[] { fieldId }, new String[] { remoteId }, new int[] { score });
+ }
+
+ // TODO(b/67867469): document
+ public static void assertFillEventForFieldsClassification(@NonNull FillEventHistory.Event event,
+ @NonNull AutofillId[] fieldIds, @NonNull String[] remoteIds, @NonNull int[] scores) {
+ assertFillEvent(event, TYPE_CONTEXT_COMMITTED, null, null, null, fieldIds, remoteIds,
+ scores);
}
// TODO(b/67867469): document
public static void assertFillEventForContextCommitted(@NonNull FillEventHistory.Event event) {
- assertFillEvent(event, TYPE_CONTEXT_COMMITTED, null, null, null, null, -1);
+ assertFillEvent(event, TYPE_CONTEXT_COMMITTED, null, null, null, null, null, null);
}
private Helper() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
index e1100e8..61bcdf2 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
@@ -72,6 +72,11 @@
}
@Test
+ public void testAdd_duplicatedValue() {
+ assertThrows(IllegalStateException.class, () -> mBuilder.add(mRemoteId2, mValue));
+ }
+
+ @Test
public void testAdd_maximumReached() {
// Must start from 1 because first is added on builder
for (int i = 1; i < UserData.getMaxFieldClassificationIdsSize() - 1; i++) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
index 6eab0f3..7375fd9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
@@ -69,6 +69,9 @@
// Set service.
enableService();
+ // Load WebView
+ mActivity.loadWebView();
+
// Set expectations.
sReplier.addResponse(CannedFillResponse.NO_RESPONSE);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
index 8282dc1..4063e79 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
@@ -93,7 +93,7 @@
*/
@Test
public void testTranslucentActivityOnTopOfHome() throws Exception {
- if (noHomeScreen()) {
+ if (!hasHomeScreen()) {
return;
}
@@ -204,7 +204,7 @@
private void performFinishActivityWithMoveTaskToBack(String finishPoint) throws Exception {
// Make sure home activity is visible.
launchHomeActivity();
- if (!noHomeScreen()) {
+ if (hasHomeScreen()) {
mAmWmState.assertHomeActivityVisible(true /* visible */);
}
@@ -226,7 +226,7 @@
// BroadcastActivity finishes, so homeActivity is not visible afterwards
// Home must be visible.
- if (!noHomeScreen()) {
+ if (hasHomeScreen()) {
mAmWmState.waitForHomeActivityVisible();
mAmWmState.assertHomeActivityVisible(true /* visible */);
}
@@ -240,7 +240,7 @@
public void testReorderToFrontBackstack() throws Exception {
// Start with home on top
launchHomeActivity();
- if (!noHomeScreen()) {
+ if (hasHomeScreen()) {
mAmWmState.assertHomeActivityVisible(true /* visible */);
}
@@ -275,7 +275,7 @@
public void testReorderToFrontChangingStack() throws Exception {
// Start with home on top
launchHomeActivity();
- if (!noHomeScreen()) {
+ if (hasHomeScreen()) {
mAmWmState.assertHomeActivityVisible(true /* visible */);
}
@@ -288,7 +288,7 @@
// Return home
launchHomeActivity();
- if (!noHomeScreen()) {
+ if (hasHomeScreen()) {
mAmWmState.assertHomeActivityVisible(true /* visible */);
}
// Launch the launching activity from the alternate launching activity with reorder to
@@ -317,7 +317,7 @@
*/
@Test
public void testNoHistoryActivityFinishedResumedActivityNotIdle() throws Exception {
- if (noHomeScreen()) {
+ if (!hasHomeScreen()) {
return;
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
index 8dc396c..e382587 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
@@ -447,6 +447,10 @@
*/
@Test
public void testSplitscreenPortraitAppOrientationRequests() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ log("Skipping test: no multi-window support");
+ return;
+ }
requestOrientationInSplitScreen(1 /* portrait */, LANDSCAPE_ACTIVITY_NAME);
}
@@ -455,6 +459,10 @@
*/
@Test
public void testSplitscreenLandscapeAppOrientationRequests() throws Exception {
+ if (!supportsSplitScreenMultiWindow()) {
+ log("Skipping test: no multi-window support");
+ return;
+ }
requestOrientationInSplitScreen(0 /* landscape */, PORTRAIT_ACTIVITY_NAME);
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java
index af88f2c..4e77ed9 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java
@@ -210,7 +210,7 @@
TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT);
assertAssistantStackExists();
mAmWmState.waitForHomeActivityVisible();
- if (!noHomeScreen()) {
+ if (hasHomeScreen()) {
mAmWmState.assertHomeActivityVisible(true);
}
@@ -239,7 +239,7 @@
mAmWmState.waitForFocusedStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT);
assertAssistantStackExists();
mAmWmState.waitForHomeActivityVisible();
- if (!noHomeScreen()) {
+ if (hasHomeScreen()) {
mAmWmState.assertHomeActivityVisible(true);
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java
index 3a73a2a..7eb3f37 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java
@@ -32,6 +32,8 @@
import android.view.Display;
import android.view.WindowManager;
+import com.android.compatibility.common.util.PollingCheck;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -134,9 +136,19 @@
public void testMaxAspectRatioResizeableActivity() throws Exception {
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
final float expected = getAspectRatio(context);
+ final Activity testActivity = launchActivity(mMaxAspectRatioResizeableActivity);
+ PollingCheck.waitFor(testActivity::hasWindowFocus);
+
+ Display testDisplay = testActivity.findViewById(android.R.id.content).getDisplay();
+
+ // TODO(b/69982434): Fix DisplayManager NPE when getting display from Instrumentation
+ // context, then can use DisplayManager to get the aspect ratio of the correct display.
+ if (testDisplay.getDisplayId() != Display.DEFAULT_DISPLAY) {
+ return;
+ }
// Since this activity is resizeable, its aspect ratio shouldn't be less than the device's
- runAspectRatioTest(mMaxAspectRatioResizeableActivity, actual -> {
+ runTest(testActivity, actual -> {
if (aspectRatioEqual(expected, actual) || expected < actual) return;
fail("actual=" + actual + " is less than expected=" + expected);
});
diff --git a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java
index cf22ad1..6d1dc53 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java
@@ -33,7 +33,7 @@
void runAspectRatioTest(final ActivityTestRule activityRule,
final AssertAspectRatioCallback callback) {
final Activity activity = launchActivity(activityRule);
- callback.assertAspectRatio(getAspectRatio(activity));
+ runTest(activity, callback);
finishActivity(activityRule);
// TODO(b/35810513): All this rotation stuff doesn't really work yet. Need to make sure
@@ -48,6 +48,10 @@
// callback.assertAspectRatio(getAspectRatio(activity));
}
+ protected void runTest(Activity activity, AssertAspectRatioCallback callback) {
+ callback.assertAspectRatio(getAspectRatio(activity));
+ }
+
static float getAspectRatio(Context context) {
final Display display =
context.getSystemService(WindowManager.class).getDefaultDisplay();
@@ -58,7 +62,7 @@
return longSide / shortSide;
}
- private Activity launchActivity(final ActivityTestRule activityRule) {
+ protected Activity launchActivity(final ActivityTestRule activityRule) {
final Activity activity = activityRule.launchActivity(null);
waitForIdle();
return activity;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
index 4bd76f1..092eae0 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
@@ -54,7 +54,7 @@
@Test
public void testKeyguardHidesActivity() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("TestActivity");
@@ -69,7 +69,7 @@
@Test
public void testShowWhenLockedActivity() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("ShowWhenLockedActivity");
@@ -89,7 +89,7 @@
*/
@Test
public void testShowWhenLockedActivity_withDialog() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("ShowWhenLockedWithDialogActivity");
@@ -110,7 +110,7 @@
*/
@Test
public void testMultipleShowWhenLockedActivities() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("ShowWhenLockedActivity");
@@ -133,7 +133,7 @@
*/
@Test
public void testTranslucentShowWhenLockedActivity() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("ShowWhenLockedTranslucentActivity");
@@ -153,7 +153,7 @@
*/
@Test
public void testTranslucentDoesntRevealBehind() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("TestActivity");
@@ -173,7 +173,7 @@
@Test
public void testDialogShowWhenLockedActivity() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("ShowWhenLockedDialogActivity");
@@ -193,7 +193,7 @@
*/
@Test
public void testShowWhenLockedActivityWhileSplit() throws Exception {
- if (!isHandheld() || !supportsSplitScreenMultiWindow()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset() || !supportsSplitScreenMultiWindow()) {
return;
}
launchActivityInDockStack(LAUNCHING_ACTIVITY);
@@ -214,7 +214,7 @@
*/
@Test
public void testDismissKeyguardActivity() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
gotoKeyguard();
@@ -229,7 +229,7 @@
@Test
public void testDismissKeyguardActivity_method() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
final String logSeparator = clearLogcat();
@@ -246,7 +246,7 @@
@Test
public void testDismissKeyguardActivity_method_notTop() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
final String logSeparator = clearLogcat();
@@ -261,7 +261,7 @@
@Test
public void testDismissKeyguardActivity_method_turnScreenOn() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
final String logSeparator = clearLogcat();
@@ -278,7 +278,7 @@
@Test
public void testDismissKeyguard_fromShowWhenLocked_notAllowed() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
gotoKeyguard();
@@ -295,7 +295,7 @@
@Test
public void testKeyguardLock() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
gotoKeyguard();
@@ -311,7 +311,7 @@
@Test
public void testUnoccludeRotationChange() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
gotoKeyguard();
@@ -339,7 +339,7 @@
@Test
public void testDismissKeyguardAttrActivity_method_turnScreenOn() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
@@ -359,7 +359,7 @@
@Test
public void testDismissKeyguardAttrActivity_method_turnScreenOn_withSecureKeyguard() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
@@ -379,7 +379,7 @@
@Test
public void testScreenOffWhileOccludedStopsActivity() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
@@ -397,7 +397,7 @@
@Test
public void testScreenOffCausesSingleStop() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
index 2abae6a..3520f52 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
@@ -44,7 +44,7 @@
@Test
public void testUnlock() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("TestActivity");
@@ -56,7 +56,7 @@
}
@Test
public void testUnlockWallpaper() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("WallpaperActivity");
@@ -68,7 +68,7 @@
}
@Test
public void testOcclude() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
gotoKeyguard();
@@ -79,7 +79,7 @@
}
@Test
public void testUnocclude() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
gotoKeyguard();
@@ -92,7 +92,7 @@
}
@Test
public void testNewActivityDuringOccluded() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
launchActivity("ShowWhenLockedActivity");
@@ -104,7 +104,7 @@
}
@Test
public void testOccludeManifestAttr() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
@@ -120,7 +120,7 @@
}
@Test
public void testOccludeAttrRemove() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
@@ -142,7 +142,7 @@
}
@Test
public void testNewActivityDuringOccludedWithAttr() throws Exception {
- if (!isHandheld()) {
+ if (!isHandheld() || isUiModeLockedToVrHeadset()) {
return;
}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
index 5e9a465..40ecfff 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
@@ -113,6 +113,11 @@
private static final String DEFAULT_COMPONENT_NAME = "android.server.am";
+ private static final int UI_MODE_TYPE_MASK = 0x0f;
+ private static final int UI_MODE_TYPE_VR_HEADSET = 0x07;
+
+ private static Boolean sHasHomeScreen = null;
+
// TODO: Remove this when all activity name are specified by {@link ComponentName}.
static String componentName = DEFAULT_COMPONENT_NAME;
@@ -568,13 +573,43 @@
return mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600;
}
+ // TODO: Switch to using a feature flag, when available.
+ protected boolean isUiModeLockedToVrHeadset() {
+ final String output = runCommandAndPrintOutput("dumpsys uimode");
+
+ Integer curUiMode = null;
+ Boolean uiModeLocked = null;
+ for (String line : output.split("\\n")) {
+ line = line.trim();
+ Matcher matcher = sCurrentUiModePattern.matcher(line);
+ if (matcher.find()) {
+ curUiMode = Integer.parseInt(matcher.group(1), 16);
+ }
+ matcher = sUiModeLockedPattern.matcher(line);
+ if (matcher.find()) {
+ uiModeLocked = matcher.group(1).equals("true");
+ }
+ }
+
+ boolean uiModeLockedToVrHeadset = (curUiMode != null) && (uiModeLocked != null)
+ && ((curUiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET) && uiModeLocked;
+
+ if (uiModeLockedToVrHeadset) {
+ log("UI mode is locked to VR headset");
+ }
+
+ return uiModeLockedToVrHeadset;
+ }
+
protected boolean supportsSplitScreenMultiWindow() {
return ActivityManager.supportsSplitScreenMultiWindow(mContext);
}
- protected boolean noHomeScreen() {
- String output = executeShellCommand(AM_NO_HOME_SCREEN);
- return output.startsWith("true");
+ protected boolean hasHomeScreen() {
+ if (sHasHomeScreen == null) {
+ sHasHomeScreen = !executeShellCommand(AM_NO_HOME_SCREEN).startsWith("true");
+ }
+ return sHasHomeScreen;
}
/**
@@ -1101,6 +1136,9 @@
+ " orientation=(\\d+)");
private static final Pattern sDisplayStatePattern =
Pattern.compile("Display Power: state=(.+)");
+ private static final Pattern sCurrentUiModePattern = Pattern.compile("mCurUiMode=0x(\\d+)");
+ private static final Pattern sUiModeLockedPattern =
+ Pattern.compile("mUiModeLocked=(true|false)");
class ReportedSizes {
int widthDp;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ParentChildTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/ParentChildTestBase.java
index 2fda508..48fe59a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ParentChildTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ParentChildTestBase.java
@@ -57,6 +57,10 @@
void doDockedTest(String testCase, ParentChildTest t) throws Exception {
log("Running test docked");
+ if (!supportsSplitScreenMultiWindow()) {
+ log("Skipping test: no split multi-window support");
+ return;
+ }
startTestCaseDocked(testCase);
doSingleTest(t);
stopTestCase();
diff --git a/tests/tests/appwidget/AndroidManifest.xml b/tests/tests/appwidget/AndroidManifest.xml
index 6f7d053..e7e7944 100644
--- a/tests/tests/appwidget/AndroidManifest.xml
+++ b/tests/tests/appwidget/AndroidManifest.xml
@@ -38,6 +38,30 @@
android:resource="@xml/second_appwidget_info" />
</receiver>
+ <receiver android:name="android.appwidget.cts.provider.AppWidgetProviderWithFeatures$Provider1" >
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_info_with_feature1" />
+ </receiver>
+
+ <receiver android:name="android.appwidget.cts.provider.AppWidgetProviderWithFeatures$Provider2" >
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_info_with_feature2" />
+ </receiver>
+
+ <receiver android:name="android.appwidget.cts.provider.AppWidgetProviderWithFeatures$Provider3" >
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_info_with_feature3" />
+ </receiver>
+
<service android:name="android.appwidget.cts.service.MyAppWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS">
</service>
diff --git a/tests/tests/appwidget/res/xml/appwidget_info_with_feature1.xml b/tests/tests/appwidget/res/xml/appwidget_info_with_feature1.xml
new file mode 100644
index 0000000..cadb283
--- /dev/null
+++ b/tests/tests/appwidget/res/xml/appwidget_info_with_feature1.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="@dimen/first_min_appwidget_size"
+ android:minHeight="@dimen/first_min_appwidget_size"
+ android:minResizeWidth="@dimen/first_min_resize_appwidget_size"
+ android:minResizeHeight="@dimen/first_min_resize_appwidget_size"
+ android:updatePeriodMillis="@integer/first_update_period_millis"
+ android:configure="android.appwidget.cts.provider.FirstAppWidgetConfigureActivity"
+ android:resizeMode="horizontal|vertical"
+ android:widgetCategory="home_screen|keyguard"
+ android:widgetFeatures="reconfigurable"
+ android:initialLayout="@layout/first_initial_layout"
+ android:initialKeyguardLayout="@layout/first_initial_keyguard_layout"
+ android:previewImage="@drawable/first_android_icon"
+ android:autoAdvanceViewId="@id/first_auto_advance_view_id">
+</appwidget-provider>
diff --git a/tests/tests/appwidget/res/xml/appwidget_info_with_feature2.xml b/tests/tests/appwidget/res/xml/appwidget_info_with_feature2.xml
new file mode 100644
index 0000000..89d60eb
--- /dev/null
+++ b/tests/tests/appwidget/res/xml/appwidget_info_with_feature2.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="@dimen/first_min_appwidget_size"
+ android:minHeight="@dimen/first_min_appwidget_size"
+ android:minResizeWidth="@dimen/first_min_resize_appwidget_size"
+ android:minResizeHeight="@dimen/first_min_resize_appwidget_size"
+ android:updatePeriodMillis="@integer/first_update_period_millis"
+ android:configure="android.appwidget.cts.provider.FirstAppWidgetConfigureActivity"
+ android:resizeMode="horizontal|vertical"
+ android:widgetCategory="home_screen|keyguard"
+ android:widgetFeatures="hide_from_picker"
+ android:initialLayout="@layout/first_initial_layout"
+ android:initialKeyguardLayout="@layout/first_initial_keyguard_layout"
+ android:previewImage="@drawable/first_android_icon"
+ android:autoAdvanceViewId="@id/first_auto_advance_view_id">
+</appwidget-provider>
diff --git a/tests/tests/appwidget/res/xml/appwidget_info_with_feature3.xml b/tests/tests/appwidget/res/xml/appwidget_info_with_feature3.xml
new file mode 100644
index 0000000..25936ab
--- /dev/null
+++ b/tests/tests/appwidget/res/xml/appwidget_info_with_feature3.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="@dimen/first_min_appwidget_size"
+ android:minHeight="@dimen/first_min_appwidget_size"
+ android:minResizeWidth="@dimen/first_min_resize_appwidget_size"
+ android:minResizeHeight="@dimen/first_min_resize_appwidget_size"
+ android:updatePeriodMillis="@integer/first_update_period_millis"
+ android:configure="android.appwidget.cts.provider.FirstAppWidgetConfigureActivity"
+ android:resizeMode="horizontal|vertical"
+ android:widgetCategory="home_screen|keyguard"
+ android:widgetFeatures="reconfigurable|hide_from_picker"
+ android:initialLayout="@layout/first_initial_layout"
+ android:initialKeyguardLayout="@layout/first_initial_keyguard_layout"
+ android:previewImage="@drawable/first_android_icon"
+ android:autoAdvanceViewId="@id/first_auto_advance_view_id">
+</appwidget-provider>
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
index 747a8bd..acafd7d 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
@@ -33,6 +33,7 @@
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.appwidget.cts.provider.AppWidgetProviderCallbacks;
+import android.appwidget.cts.provider.AppWidgetProviderWithFeatures;
import android.appwidget.cts.provider.FirstAppWidgetProvider;
import android.appwidget.cts.provider.SecondAppWidgetProvider;
import android.appwidget.cts.service.MyAppWidgetService;
@@ -1308,6 +1309,25 @@
}
}
+ public void testWidgetFeaturesParsed() throws Exception {
+ if (!hasAppWidgets()) {
+ return;
+ }
+ assertEquals(0, getFirstAppWidgetProviderInfo().widgetFeatures);
+ String packageName = getInstrumentation().getTargetContext().getPackageName();
+
+ assertEquals(AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE,
+ getProviderInfo(new ComponentName(packageName,
+ AppWidgetProviderWithFeatures.Provider1.class.getName())).widgetFeatures);
+ assertEquals(AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER,
+ getProviderInfo(new ComponentName(packageName,
+ AppWidgetProviderWithFeatures.Provider2.class.getName())).widgetFeatures);
+ assertEquals(AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
+ | AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER,
+ getProviderInfo(new ComponentName(packageName,
+ AppWidgetProviderWithFeatures.Provider3.class.getName())).widgetFeatures);
+ }
+
private void waitForCallCount(AtomicInteger counter, int expectedCount) {
synchronized (mLock) {
final long startTimeMillis = SystemClock.uptimeMillis();
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/provider/AppWidgetProviderWithFeatures.java b/tests/tests/appwidget/src/android/appwidget/cts/provider/AppWidgetProviderWithFeatures.java
new file mode 100644
index 0000000..d1f848a
--- /dev/null
+++ b/tests/tests/appwidget/src/android/appwidget/cts/provider/AppWidgetProviderWithFeatures.java
@@ -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.
+ */
+
+package android.appwidget.cts.provider;
+
+public abstract class AppWidgetProviderWithFeatures extends StubbableAppWidgetProvider {
+ private static final Object sLock = new Object();
+
+ private static AppWidgetProviderCallbacks sCallbacks;
+
+ public static void setCallbacks(AppWidgetProviderCallbacks callbacks) {
+ synchronized (sLock) {
+ sCallbacks = callbacks;
+ }
+ }
+
+ @Override
+ protected AppWidgetProviderCallbacks getCallbacks() {
+ synchronized (sLock) {
+ if (sCallbacks != null) {
+ sCallbacks.setProvider(this);
+ }
+ return sCallbacks;
+ }
+ }
+
+ public static final class Provider1 extends AppWidgetProviderWithFeatures { }
+
+ public static final class Provider2 extends AppWidgetProviderWithFeatures { }
+
+ public static final class Provider3 extends AppWidgetProviderWithFeatures { }
+}
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index 5185fdb..73252db 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -41,6 +41,7 @@
import android.content.res.Resources;
import android.media.AudioManager;
import android.content.pm.PackageManager;
+import android.media.AudioSystem;
import android.media.MediaPlayer;
import android.os.Vibrator;
import android.provider.Settings;
@@ -59,6 +60,8 @@
private boolean mHasVibrator;
private boolean mUseFixedVolume;
private boolean mIsTelevision;
+ private boolean mIsSingleVolume;
+ private boolean mSkipRingerTests;
private Context mContext;
private final static int ASYNC_TIMING_TOLERANCE_MS = 50;
@@ -77,6 +80,9 @@
mIsTelevision = packageManager != null
&& (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
|| packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION));
+ mIsSingleVolume = mContext.getResources().getBoolean(
+ Resources.getSystem().getIdentifier("config_single_volume", "bool", "android"));
+ mSkipRingerTests = mUseFixedVolume || mIsTelevision || mIsSingleVolume;
}
@Override
protected void tearDown() throws Exception {
@@ -156,6 +162,9 @@
}
public void testMusicActive() throws Exception {
+ if (mAudioManager.isMusicActive()) {
+ return;
+ }
MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY);
assertNotNull(mp);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
@@ -353,14 +362,14 @@
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
// AudioService#setRingerMode() has:
// if (isTelevision) return;
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} else {
assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode());
}
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} else {
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
@@ -369,7 +378,7 @@
}
public void testSetRingerModePolicyAccess() throws Exception {
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
return;
}
// Apps without policy access cannot change silent -> normal or silent -> vibrate.
@@ -432,7 +441,7 @@
}
public void testVolumeDndAffectedStream() throws Exception {
- if (mUseFixedVolume || mHasVibrator || mIsTelevision) {
+ if (mHasVibrator || mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
@@ -575,6 +584,11 @@
mAudioManager.adjustVolume(ADJUST_RAISE, 0);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
+ boolean isMusicPlayingBeforeTest = false;
+ if (mAudioManager.isMusicActive()) {
+ isMusicPlayingBeforeTest = true;
+ }
+
MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY);
assertNotNull(mp);
mp.setAudioStreamType(STREAM_MUSIC);
@@ -610,7 +624,9 @@
mp.stop();
mp.release();
Thread.sleep(TIME_TO_PLAY);
- assertFalse(mAudioManager.isMusicActive());
+ if (!isMusicPlayingBeforeTest) {
+ assertFalse(mAudioManager.isMusicActive());
+ }
}
public void testAccessibilityVolume() throws Exception {
@@ -680,7 +696,7 @@
}
public void testMuteDndAffectedStreams() throws Exception {
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
return;
}
int[] streams = { AudioManager.STREAM_RING };
@@ -754,7 +770,7 @@
}
public void testMuteDndUnaffectedStreams() throws Exception {
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
return;
}
int[] streams = {
@@ -840,7 +856,7 @@
}
public void testAdjustVolumeInTotalSilenceMode() throws Exception {
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
return;
}
try {
@@ -860,7 +876,7 @@
}
public void testAdjustVolumeInAlarmsOnlyMode() throws Exception {
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
return;
}
try {
@@ -883,7 +899,7 @@
}
public void testSetStreamVolumeInTotalSilenceMode() throws Exception {
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
return;
}
try {
@@ -905,7 +921,7 @@
}
public void testSetStreamVolumeInAlarmsOnlyMode() throws Exception {
- if (mUseFixedVolume || mIsTelevision) {
+ if (mSkipRingerTests) {
return;
}
try {
diff --git a/tests/tests/security/res/raw/bug_65483665.mp4 b/tests/tests/security/res/raw/bug_65483665.mp4
new file mode 100644
index 0000000..105e274
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_65483665.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_69478425.mp4 b/tests/tests/security/res/raw/bug_69478425.mp4
new file mode 100644
index 0000000..b8ff0c5
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_69478425.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index bb7e455..62ca28d 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -247,6 +247,11 @@
***********************************************************/
@SecurityTest
+ public void testStagefright_bug_65483665() throws Exception {
+ doStagefrightTest(R.raw.bug_65483665);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2017_0852_b_62815506() throws Exception {
doStagefrightTest(R.raw.cve_2017_0852_b_62815506);
}
@@ -257,6 +262,11 @@
***********************************************************/
@SecurityTest
+ public void testStagefright_bug_69478425() throws Exception {
+ doStagefrightTest(R.raw.bug_69478425);
+ }
+
+ @SecurityTest
public void testStagefright_bug_65717533() throws Exception {
doStagefrightTest(R.raw.bug_65717533_header_corrupt);
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 79d5ec3..32be1c9 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -2100,7 +2100,7 @@
}
final String p = "<p style=\"height:1000px;width:1000px\">Test setInitialScale.</p>";
final float defaultScale =
- getInstrumentation().getTargetContext().getResources().getDisplayMetrics().density;
+ getActivity().getResources().getDisplayMetrics().density;
mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
+ "</body></html>", "text/html", null);
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
index b447e9d..51e6102 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -125,9 +125,9 @@
@Before
public void setup() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mContext = mInstrumentation.getTargetContext();
-
final Activity activity = mActivityRule.getActivity();
+ // Always use the activity context
+ mContext = activity;
PollingCheck.waitFor(activity::hasWindowFocus);
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java b/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java
index 64b1693..ee6dc39 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java
@@ -97,7 +97,7 @@
mActivityRule.runOnUiThread(() -> mListView.setAdapter(mCountriesAdapter));
mInstrumentation.waitForIdleSync();
- mRowHeightPx = mContext.getResources().getDimensionPixelSize(R.dimen.listrow_height);
+ mRowHeightPx = activity.getResources().getDimensionPixelSize(R.dimen.listrow_height);
}
/**
diff --git a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
index d3943e5..ce093e7 100644
--- a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
@@ -776,6 +776,12 @@
: (TimePicker) mActivity.findViewById(R.id.timepicker_spinner);
mActivityRule.runOnUiThread(() -> {
+ /* hide one of the widgets to assure they fit onto the screen */
+ if (isClockMode) {
+ mActivity.findViewById(R.id.timepicker_spinner).setVisibility(View.GONE);
+ } else {
+ mActivity.findViewById(R.id.timepicker_clock).setVisibility(View.GONE);
+ }
mTimePicker.setIs24HourView(is24hFormat);
mTimePicker.setHour(initialHour);
mTimePicker.setMinute(initialMinute);
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 4f36b8f..f20f190 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -94,6 +94,7 @@
checkFile ${JAR_DIR}/${JAR}.jar
JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
done
+JAR_PATH=${JAR_PATH:1} # Strip off leading ':'
OPTIONAL_JARS="
google-tradefed