Merge "Add isAutomotive and isVrHeadset to device-side FeatureUtil" into stage-aosp-pi-cts-dev
am: 46f2ea1b71
Change-Id: I0f576f8e44181e80768873aa27a4dfde6535a62c
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 7f367db..f01fbde 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.verifier"
android:versionCode="5"
- android:versionName="9.0_r2">
+ android:versionName="9.0_r1">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28"/>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java
index 531b40b..e25f758 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java
@@ -57,11 +57,19 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // skip current test if device doesn't support cellular
+ if (!EmergencyCallUtil.isPhoneDevice(this)) {
+ String skipInfo = getResources().getString(R.string.emergency_call_skip_info);
+ TestResult.setPassedResult(this, super.getClass().getName(), skipInfo);
+ Toast toast = Toast.makeText(getApplicationContext(), skipInfo, Toast.LENGTH_LONG);
+ toast.show();
+ this.finish();
+ return;
+ }
// override the test info
mTextView.setText(R.string.location_emergency_call_test_info);
EmergencyCallUtil.setDefaultDialer(this, this.getPackageName());
setPassFailButtonClickListeners();
-
}
@Override
@@ -74,15 +82,7 @@
@Override
public void onClick(View target) {
- // skip current test if device doesn't support cellular
- if (!EmergencyCallUtil.isPhoneDevice(this)) {
- String skipInfo = getResources().getString(R.string.emergency_call_skip_info);
- TestResult.setPassedResult(this, super.getClass().getName(), skipInfo);
- Toast toast = Toast.makeText(getApplicationContext(), skipInfo, Toast.LENGTH_LONG);
- toast.show();
- this.finish();
- return;
- }
+
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final FrameLayout frameView = new FrameLayout(this);
builder.setView(frameView);
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
index 1282bd0..4b3ae9a 100755
--- a/hostsidetests/security/AndroidTest.xml
+++ b/hostsidetests/security/AndroidTest.xml
@@ -57,6 +57,7 @@
<!-- Bulletin 2016-09 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2015-8839->/data/local/tmp/CVE-2015-8839" />
<option name="push" value="CVE-2016-2471->/data/local/tmp/CVE-2016-2471" />
<!--__________________-->
diff --git a/hostsidetests/security/securityPatch/CVE-2015-8839/Android.mk b/hostsidetests/security/securityPatch/CVE-2015-8839/Android.mk
new file mode 100755
index 0000000..65fe025
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2015-8839/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CVE-2015-8839
+LOCAL_SRC_FILES := poc.c
+
+LOCAL_SHARED_LIBRARIES := libcutils \
+ liblog
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_LDFLAGS += -fPIE -pie
+LOCAL_LDFLAGS += -rdynamic
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2015-8839/poc.c b/hostsidetests/security/securityPatch/CVE-2015-8839/poc.c
new file mode 100755
index 0000000..c6a330f
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2015-8839/poc.c
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+#include <cutils/log.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/falloc.h>
+#include <linux/magic.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+int main(void) {
+ int fd = -1, result = -1;
+ char tmpFile[32];
+ struct statfs sfs;
+
+ memset(tmpFile, 0, sizeof(tmpFile));
+ strncpy(tmpFile, "/data/local/tmp/tmpFile", 24);
+
+ fd = open(tmpFile, O_WRONLY | O_APPEND | O_CREAT, 0644);
+ if (fd < 0) {
+ ALOGE("Creation of tmp file is failed [%s]", strerror(errno));
+ return -1;
+ }
+
+ fstatfs(fd, &sfs);
+ if (sfs.f_type == EXT4_SUPER_MAGIC) {
+ result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1);
+ if (result < 0 && errno == EOPNOTSUPP) {
+ ALOGD("fallocate result [%s] errno [%d]", strerror(errno), errno);
+ ALOGE("fallocate result EOPNOTSUPP");
+ }
+ }
+
+ if (fd) {
+ close(fd);
+ }
+
+ return 0;
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc16_09.java b/hostsidetests/security/src/android/security/cts/Poc16_09.java
index 7ab08ad..5cd86bd 100644
--- a/hostsidetests/security/src/android/security/cts/Poc16_09.java
+++ b/hostsidetests/security/src/android/security/cts/Poc16_09.java
@@ -26,4 +26,15 @@
public void testPocCVE_2016_2471() throws Exception {
AdbUtils.runPoc("CVE-2016-2471", getDevice(), 60);
}
+
+ /**
+ * b/28760453
+ */
+ @SecurityTest
+ public void testPocCVE_2015_8839() throws Exception {
+ AdbUtils.runCommandLine("logcat -c" , getDevice());
+ AdbUtils.runPoc("CVE-2015-8839", getDevice(), 60);
+ String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
+ assertMatches("[\\s\\n\\S]*fallocate result EOPNOTSUPP[\\s\\n\\S]*", logcat);
+ }
}
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_03.java b/hostsidetests/security/src/android/security/cts/Poc17_03.java
index 80c959c..a6f1e04 100644
--- a/hostsidetests/security/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/security/src/android/security/cts/Poc17_03.java
@@ -82,4 +82,23 @@
assertNotMatchesMultiLine(".*Fatal signal 11 \\(SIGSEGV\\).*>>> /system/bin/" +
"audioserver <<<.*", logcatOut);
}
+
+ /*
+ * b/33178389
+ */
+ @SecurityTest
+ public void testPocCVE_2017_0490() throws Exception {
+ String bootCountBefore =
+ AdbUtils.runCommandLine("settings get global boot_count", getDevice());
+ AdbUtils.runCommandLine("service call wifi 43 s16 content://settings/global/boot_count s16 "
+ + "\"application/x-wifi-config\"",
+ getDevice());
+ String bootCountAfter =
+ AdbUtils.runCommandLine("settings get global boot_count", getDevice());
+ // Poc nukes the boot_count setting, reboot to restore it to a sane value
+ AdbUtils.runCommandLine("reboot", getDevice());
+ getDevice().waitForDeviceOnline(60 * 1000);
+ updateKernelStartTime();
+ assertEquals(bootCountBefore, bootCountAfter);
+ }
}
diff --git a/hostsidetests/security/src/android/security/cts/SecurityTestCase.java b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
index cacceaa..e296f4c 100644
--- a/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
@@ -23,6 +23,9 @@
import com.android.tradefed.log.LogUtil.CLog;
import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.Map;
+import java.util.HashMap;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.Log;
@@ -31,7 +34,29 @@
private static final String LOG_TAG = "SecurityTestCase";
private long kernelStartTime;
- private static Thread checkOom = null;
+
+ private static final long LOW_MEMORY_DEVICE_THRESHOLD_KB = 1024 * 1024; // 1GB
+ private boolean isLowMemoryDevice = false;
+ private static Map<ITestDevice, OomCatcher> oomCatchers = new HashMap<>();
+ private static Map<ITestDevice, Long> totalMemories = new HashMap<>();
+ private enum OomBehavior {
+ FAIL_AND_LOG, // normal behavior
+ PASS_AND_LOG, // skip tests that oom low memory devices
+ FAIL_NO_LOG, // tests that check for oom
+ }
+ private OomBehavior oomBehavior = OomBehavior.FAIL_AND_LOG; // accessed across threads
+ private boolean oomDetected = false; // accessed across threads
+
+ private static long getMemTotal(ITestDevice device) throws Exception {
+ String memInfo = device.executeShellCommand("cat /proc/meminfo");
+ Pattern pattern = Pattern.compile("MemTotal:\\s*(.*?)\\s*[kK][bB]");
+ Matcher matcher = pattern.matcher(memInfo);
+ if (matcher.find()) {
+ return Long.parseLong(matcher.group(1));
+ } else {
+ throw new Exception("Could not get device memory total");
+ }
+ }
/**
* Waits for device to be online, marks the most recent boottime of the device
@@ -46,11 +71,35 @@
//TODO:(badash@): Watch for other things to track.
// Specifically time when app framework starts
- // Start Out of Memory detection in separate thread
- //if (checkOom == null || !checkOom.isAlive()) {
- // checkOom = new Thread(new OomChecker());
- // checkOom.start();
- //}
+ // Singleton for caching device TotalMem to avoid and adb shell for every test.
+ Long totalMemory = totalMemories.get(getDevice());
+ if (totalMemory == null) {
+ totalMemory = getMemTotal(getDevice());
+ totalMemories.put(getDevice(), totalMemory);
+ }
+ isLowMemoryDevice = totalMemory < LOW_MEMORY_DEVICE_THRESHOLD_KB;
+
+ // reset test oom behavior
+ // Low memory devices should skip (pass) tests when OOMing and log so that the
+ // high-memory-test flag can be added. Normal devices should fail tests that OOM so that
+ // they'll be ran again with --retry. If the test OOMs because previous tests used the
+ // memory, it will likely pass on a second try.
+ synchronized (this) { // synchronized for oomBehavior and oomDetected.
+ if (isLowMemoryDevice) {
+ oomBehavior = OomBehavior.PASS_AND_LOG;
+ } else {
+ oomBehavior = OomBehavior.FAIL_AND_LOG;
+ }
+ oomDetected = false;
+ }
+
+ // Singleton OOM detection in separate persistent threads for each device.
+ OomCatcher oomCatcher = oomCatchers.get(getDevice());
+ if (oomCatcher == null || !oomCatcher.isAlive()) {
+ oomCatcher = new OomCatcher();
+ oomCatchers.put(getDevice(), oomCatcher);
+ oomCatcher.start();
+ }
}
/**
@@ -102,6 +151,23 @@
- kernelStartTime < 2));
//TODO(badash@): add ability to catch runtime restart
getDevice().disableAdbRoot();
+
+ // pass, fail, or log based on the oom behavior
+ synchronized (this) { // synchronized for oomDetected and oomBehavior
+ if (oomDetected) {
+ switch (oomBehavior) {
+ case FAIL_AND_LOG:
+ fail("The device ran out of memory.");
+ return;
+ case PASS_AND_LOG:
+ Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG, "Skipping test.");
+ return;
+ case FAIL_NO_LOG:
+ fail();
+ return;
+ }
+ }
+ }
}
public void assertMatches(String pattern, String input) throws Exception {
@@ -118,7 +184,26 @@
Pattern.DOTALL).matcher(input).matches());
}
- class OomChecker implements Runnable {
+ // Flag meaning the test will likely fail on devices with low memory.
+ public void setHighMemoryTest() {
+ synchronized (this) { // synchronized for oomBehavior
+ if (isLowMemoryDevice) {
+ oomBehavior = OomBehavior.PASS_AND_LOG;
+ } else {
+ oomBehavior = OomBehavior.FAIL_AND_LOG;
+ }
+ }
+ }
+
+ // Flag meaning the test uses the OOM catcher to fail the test because the test vulnerability
+ // intentionally OOMs the device.
+ public void setOomTest() {
+ synchronized (this) { // synchronized for oomBehavior
+ oomBehavior = OomBehavior.FAIL_NO_LOG;
+ }
+ }
+
+ class OomCatcher extends Thread {
@Override
public void run() {
@@ -130,7 +215,11 @@
if (Pattern.matches(".*lowmemorykiller.*", line)) {
// low memory detected, reboot device to clear memory and pass test
isCancelled = true;
- Log.i(LOG_TAG, "lowmemorykiller detected; rebooting device and passing test");
+ Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+ "lowmemorykiller detected; rebooting device.");
+ synchronized (SecurityTestCase.this) { // synchronized for oomDetected
+ oomDetected = true;
+ }
try {
getDevice().rebootUntilOnline();
updateKernelStartTime();
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index cce6171..47020ed 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -2010,15 +2010,20 @@
case RAW: {
Size targetSize = (numConfigs == 1) ? maxSizes.maxRawSize :
overridePhysicalCameraSizes.get(j);
- ImageReader target = ImageReader.newInstance(
- targetSize.getWidth(), targetSize.getHeight(), RAW, numBuffers);
- target.setOnImageAvailableListener(imageDropperListener, mHandler);
- OutputConfiguration config = new OutputConfiguration(target.getSurface());
- if (numConfigs > 1) {
- config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+ // targetSize could be null in the logical camera case where only
+ // physical camera supports RAW stream.
+ if (targetSize != null) {
+ ImageReader target = ImageReader.newInstance(
+ targetSize.getWidth(), targetSize.getHeight(), RAW, numBuffers);
+ target.setOnImageAvailableListener(imageDropperListener, mHandler);
+ OutputConfiguration config =
+ new OutputConfiguration(target.getSurface());
+ if (numConfigs > 1) {
+ config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+ }
+ outputConfigs.add(config);
+ rawTargets.add(target);
}
- outputConfigs.add(config);
- rawTargets.add(target);
break;
}
default:
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 0342f08..3b28ad4 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -718,8 +718,8 @@
@SuppressWarnings("unchecked")
private void checkAttestationSecurityLevelDependentParams(Attestation attestation) {
- assertThat("Attestation version must be 1 or 2", attestation.getAttestationVersion(),
- either(is(1)).or(is(2)));
+ assertThat("Attestation version must be 1, 2, or 3", attestation.getAttestationVersion(),
+ either(is(1)).or(is(2)).or(is(3)));
AuthorizationList teeEnforced = attestation.getTeeEnforced();
AuthorizationList softwareEnforced = attestation.getSoftwareEnforced();
diff --git a/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java b/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java
index 2c549f2..151c94a 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java
@@ -95,116 +95,124 @@
assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
for (String aacDecName : sAacDecoderNames) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a running for dec=" + aacDecName);
- // test DRC effectTypeID 1 "NIGHT"
- // L -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
- // R +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
try {
- checkUsacDrcEffectType(1, 0.5011f, 1.9952f, "Night", 2, 0, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/0 failed for dec=" + aacDecName);
- throw new RuntimeException(e);
+ runDecodeUsacDrcEffectTypeM4a(aacDecName);
+ } catch (Error err) {
+ throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
}
+ }
+ }
- // test DRC effectTypeID 2 "NOISY"
- // L +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
- // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
- try {
- checkUsacDrcEffectType(2, 1.9952f, 0.2511f, "Noisy", 2, 0, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/0 failed for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
+ private void runDecodeUsacDrcEffectTypeM4a(String aacDecName) throws Exception {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a running for dec=" + aacDecName);
+ // test DRC effectTypeID 1 "NIGHT"
+ // L -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
+ // R +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
+ try {
+ checkUsacDrcEffectType(1, 0.5011f, 1.9952f, "Night", 2, 0, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/0 failed for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
- // test DRC effectTypeID 3 "LIMITED"
- // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
- // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
- try {
- checkUsacDrcEffectType(3, 0.2511f, 3.9810f, "Limited", 2, 0, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/0 failed for dec="
- + aacDecName);
- throw new RuntimeException(e);
- }
+ // test DRC effectTypeID 2 "NOISY"
+ // L +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
+ // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+ try {
+ checkUsacDrcEffectType(2, 1.9952f, 0.2511f, "Noisy", 2, 0, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/0 failed for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
- // test DRC effectTypeID 6 "GENERAL"
- // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
- // R -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
- try {
- checkUsacDrcEffectType(6, 3.9810f, 0.5011f, "General", 2, 0, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/0 failed for dec="
- + aacDecName);
- throw new RuntimeException(e);
- }
+ // test DRC effectTypeID 3 "LIMITED"
+ // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+ // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+ try {
+ checkUsacDrcEffectType(3, 0.2511f, 3.9810f, "Limited", 2, 0, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/0 failed for dec="
+ + aacDecName);
+ throw new RuntimeException(e);
+ }
- // test DRC effectTypeID 1 "NIGHT"
- // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
- // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
- // mono -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
- try {
- checkUsacDrcEffectType(1, 0.2511f, 3.9810f, "Night", 2, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
- try {
- checkUsacDrcEffectType(1, 0.2511f, 0.0f, "Night", 1, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/1/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
+ // test DRC effectTypeID 6 "GENERAL"
+ // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+ // R -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
+ try {
+ checkUsacDrcEffectType(6, 3.9810f, 0.5011f, "General", 2, 0, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/0 failed for dec="
+ + aacDecName);
+ throw new RuntimeException(e);
+ }
- // test DRC effectTypeID 2 "NOISY"
- // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
- // R -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
- // mono +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
- try {
- checkUsacDrcEffectType(2, 3.9810f, 0.1258f, "Noisy", 2, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
- try {
- checkUsacDrcEffectType(2, 3.9810f, 0.0f, "Noisy", 1, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
+ // test DRC effectTypeID 1 "NIGHT"
+ // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+ // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+ // mono -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+ try {
+ checkUsacDrcEffectType(1, 0.2511f, 3.9810f, "Night", 2, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
+ try {
+ checkUsacDrcEffectType(1, 0.2511f, 0.0f, "Night", 1, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/1/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
- // test DRC effectTypeID 3 "LIMITED"
- // L -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
- // R +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
- // mono -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
- try {
- checkUsacDrcEffectType(3, 0.1258f, 7.9432f, "Limited", 2, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
- try {
- checkUsacDrcEffectType(3, 0.1258f, 0.0f, "Limited", 1, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/1/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
+ // test DRC effectTypeID 2 "NOISY"
+ // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+ // R -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
+ // mono +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+ try {
+ checkUsacDrcEffectType(2, 3.9810f, 0.1258f, "Noisy", 2, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
+ try {
+ checkUsacDrcEffectType(2, 3.9810f, 0.0f, "Noisy", 1, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
- // test DRC effectTypeID 6 "GENERAL"
- // L +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
- // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
- // mono +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
- try {
- checkUsacDrcEffectType(6, 7.9432f, 0.2511f, "General", 2, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
- try {
- checkUsacDrcEffectType(6, 7.9432f, 0.0f, "General", 1, 1, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/1/1 for dec=" + aacDecName);
- throw new RuntimeException(e);
- }
+ // test DRC effectTypeID 3 "LIMITED"
+ // L -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
+ // R +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
+ // mono -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
+ try {
+ checkUsacDrcEffectType(3, 0.1258f, 7.9432f, "Limited", 2, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
+ try {
+ checkUsacDrcEffectType(3, 0.1258f, 0.0f, "Limited", 1, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/1/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
+
+ // test DRC effectTypeID 6 "GENERAL"
+ // L +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
+ // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+ // mono +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
+ try {
+ checkUsacDrcEffectType(6, 7.9432f, 0.2511f, "General", 2, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
+ }
+ try {
+ checkUsacDrcEffectType(6, 7.9432f, 0.0f, "General", 1, 1, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/1/1 for dec=" + aacDecName);
+ throw new RuntimeException(e);
}
}
@@ -218,52 +226,61 @@
assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
for (String aacDecName : sAacDecoderNames) {
- // Stereo
- // switch between SBR ratios and stereo modes
try {
- checkUsacStreamSwitching(2.5459829E12f, 2,
- R.raw.noise_2ch_44_1khz_aot42_19_lufs_config_change_mp4, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch sbr/stereo switch for "
- + aacDecName);
- throw new RuntimeException(e);
- }
-
- // Mono
- // switch between SBR ratios and stereo modes
- try {
- checkUsacStreamSwitching(2.24669126E12f, 1,
- R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch sbr/stereo switch for "
- + aacDecName);
- throw new RuntimeException(e);
- }
-
- // Stereo
- // switch between USAC modes
- try {
- checkUsacStreamSwitching(2.1E12f, 2,
- R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch USAC mode switch for "
- + aacDecName);
- throw new RuntimeException(e);
- }
-
- // Mono
- // switch between USAC modes
- try {
- checkUsacStreamSwitching(1.7E12f, 1,
- R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch USAC mode switch for "
- + aacDecName);
- throw new RuntimeException(e);
+ runDecodeUsacStreamSwitchingM4a(aacDecName);
+ } catch (Error err) {
+ throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
}
}
}
+ private void runDecodeUsacStreamSwitchingM4a(String aacDecName) throws Exception {
+ // Stereo
+ // switch between SBR ratios and stereo modes
+ try {
+ checkUsacStreamSwitching(2.5459829E12f, 2,
+ R.raw.noise_2ch_44_1khz_aot42_19_lufs_config_change_mp4, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch sbr/stereo switch for "
+ + aacDecName);
+ throw new RuntimeException(e);
+ }
+
+ // Mono
+ // switch between SBR ratios and stereo modes
+ try {
+ checkUsacStreamSwitching(2.24669126E12f, 1,
+ R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch sbr/stereo switch for "
+ + aacDecName);
+ throw new RuntimeException(e);
+ }
+
+ // Stereo
+ // switch between USAC modes
+ try {
+ checkUsacStreamSwitching(2.1E12f, 2,
+ R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch USAC mode switch for "
+ + aacDecName);
+ throw new RuntimeException(e);
+ }
+
+ // Mono
+ // switch between USAC modes
+ try {
+ checkUsacStreamSwitching(1.7E12f, 1,
+ R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch USAC mode switch for "
+ + aacDecName);
+ throw new RuntimeException(e);
+ }
+
+ }
+
/**
* Verify the correct decoding of USAC bitstreams with various sampling rates.
*/
@@ -275,20 +292,28 @@
for (String aacDecName : sAacDecoderNames) {
try {
- checkUsacSamplingRate(R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, aacDecName);
- checkUsacSamplingRate(R.raw.noise_2ch_12khz_aot42_19_lufs_mp4, aacDecName);
- checkUsacSamplingRate(R.raw.noise_2ch_22_05khz_aot42_19_lufs_mp4, aacDecName);
- checkUsacSamplingRate(R.raw.noise_2ch_64khz_aot42_19_lufs_mp4, aacDecName);
- checkUsacSamplingRate(R.raw.noise_2ch_88_2khz_aot42_19_lufs_mp4, aacDecName);
- checkUsacSamplingRateWoLoudness(R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4,
- aacDecName);
- } catch (Exception e) {
- Log.v(TAG, "testDecodeUsacSamplingRatesM4a for decoder" + aacDecName);
- throw new RuntimeException(e);
+ runDecodeUsacSamplingRatesM4a(aacDecName);
+ } catch (Error err) {
+ throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
}
}
}
+ private void runDecodeUsacSamplingRatesM4a(String aacDecName) throws Exception {
+ try {
+ checkUsacSamplingRate(R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, aacDecName);
+ checkUsacSamplingRate(R.raw.noise_2ch_12khz_aot42_19_lufs_mp4, aacDecName);
+ checkUsacSamplingRate(R.raw.noise_2ch_22_05khz_aot42_19_lufs_mp4, aacDecName);
+ checkUsacSamplingRate(R.raw.noise_2ch_64khz_aot42_19_lufs_mp4, aacDecName);
+ checkUsacSamplingRate(R.raw.noise_2ch_88_2khz_aot42_19_lufs_mp4, aacDecName);
+ checkUsacSamplingRateWoLoudness(R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4,
+ aacDecName);
+ } catch (Exception e) {
+ Log.v(TAG, "testDecodeUsacSamplingRatesM4a for decoder" + aacDecName);
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* Internal utilities
@@ -440,7 +465,7 @@
}
/**
- * Same as {@link #checkEnergyUSAC(short[], AudioParameter, int, int)} but with DRC effec type
+ * Same as {@link #checkEnergyUSAC(short[], AudioParameter, int, int)} but with DRC effect type
* @param decSamples
* @param decParams
* @param encNch
diff --git a/tests/tests/notificationlegacy/AndroidManifest.xml b/tests/tests/notificationlegacy/AndroidManifest.xml
index 7b55bc8..dd96eac 100644
--- a/tests/tests/notificationlegacy/AndroidManifest.xml
+++ b/tests/tests/notificationlegacy/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.app.notification.legacy.cts">
+ <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" />
<application>
@@ -30,6 +31,24 @@
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
+
+ <service android:name="android.app.notification.legacy.cts.LegacyConditionProviderService"
+ android:exported="true"
+ android:label="Legacy"
+ android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.ConditionProviderService" />
+ </intent-filter>
+ </service>
+
+ <service android:name="android.app.notification.legacy.cts.SecondaryConditionProviderService"
+ android:exported="true"
+ android:label="Secondary"
+ android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.ConditionProviderService" />
+ </intent-filter>
+ </service>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
new file mode 100644
index 0000000..7a172e5
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.notification.legacy.cts;
+
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
+import static android.service.notification.NotificationListenerService.INTERRUPTION_FILTER_PRIORITY;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import android.app.ActivityManager;
+import android.app.AutomaticZenRule;
+import android.app.Instrumentation;
+import android.app.NotificationManager;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@RunWith(AndroidJUnit4.class)
+public class ConditionProviderServiceTest {
+ private static String TAG = "CpsTest";
+
+ private NotificationManager mNm;
+ private ActivityManager mActivityManager;
+ private Context mContext;
+ private ArraySet<String> ids = new ArraySet<>();
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ toggleNotificationPolicyAccess(mContext.getPackageName(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ LegacyConditionProviderService.requestRebind(LegacyConditionProviderService.getId());
+ SecondaryConditionProviderService.requestRebind(SecondaryConditionProviderService.getId());
+ mNm = (NotificationManager) mContext.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ mNm.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ try {
+ for (String id : ids) {
+ if (id != null) {
+ if (!mNm.removeAutomaticZenRule(id)) {
+ throw new Exception("Could not remove rule " + id);
+ }
+
+ assertNull(mNm.getAutomaticZenRule(id));
+ }
+ }
+ } finally {
+ toggleNotificationPolicyAccess(mContext.getPackageName(),
+ InstrumentationRegistry.getInstrumentation(), false);
+ pollForConnection(LegacyConditionProviderService.class, false);
+ pollForConnection(SecondaryConditionProviderService.class, false);
+ }
+ }
+
+ @Test
+ public void testUnboundCPSMaintainsCondition_addsNewRule() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ return;
+ }
+
+ // make sure service get bound
+ pollForConnection(SecondaryConditionProviderService.class, true);
+
+ final ComponentName cn = SecondaryConditionProviderService.getId();
+
+ // add rule
+ addRule(cn, INTERRUPTION_FILTER_ALARMS, true);
+ pollForSubscribe(SecondaryConditionProviderService.getInstance());
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+ // unbind service
+ SecondaryConditionProviderService.getInstance().requestUnbind();
+
+ // verify that DND state doesn't change
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+ // add a new rule
+ addRule(cn, INTERRUPTION_FILTER_NONE, true);
+
+ // verify that the unbound service maintains it's DND vote
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+ }
+
+ @Test
+ public void testUnboundCPSMaintainsCondition_otherConditionChanges() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ return;
+ }
+
+ // make sure both services get bound
+ pollForConnection(LegacyConditionProviderService.class, true);
+ pollForConnection(SecondaryConditionProviderService.class, true);
+
+ // add rules for both
+ addRule(LegacyConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, true);
+ pollForSubscribe(LegacyConditionProviderService.getInstance());
+
+ addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_ALARMS, true);
+ pollForSubscribe(SecondaryConditionProviderService.getInstance());
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+ // unbind one of the services
+ SecondaryConditionProviderService.getInstance().requestUnbind();
+
+ // verify that DND state doesn't change
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+ // trigger a change in the bound service's condition
+ ((LegacyConditionProviderService) LegacyConditionProviderService.getInstance())
+ .toggleDND(false);
+
+ // verify that the unbound service maintains it's DND vote
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+ }
+
+ @Test
+ public void testUnboundCPSMaintainsCondition_otherProviderRuleChanges() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ return;
+ }
+
+ // make sure both services get bound
+ pollForConnection(LegacyConditionProviderService.class, true);
+ pollForConnection(SecondaryConditionProviderService.class, true);
+
+ // add rules for both
+ addRule(LegacyConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, true);
+ pollForSubscribe(LegacyConditionProviderService.getInstance());
+
+ addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_ALARMS, true);
+ pollForSubscribe(SecondaryConditionProviderService.getInstance());
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+ // unbind one of the services
+ SecondaryConditionProviderService.getInstance().requestUnbind();
+
+ // verify that DND state doesn't change
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+ // trigger a change in the bound service's rule
+ addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, false);
+
+ // verify that the unbound service maintains it's DND vote
+ assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+ }
+
+ private void addRule(ComponentName cn, int filter, boolean enabled) {
+ String id = mNm.addAutomaticZenRule(new AutomaticZenRule("name",
+ cn, Uri.EMPTY, filter, enabled));
+ Log.d(TAG, "Created rule with id " + id);
+ ids.add(id);
+ }
+
+ private void toggleNotificationPolicyAccess(String packageName,
+ Instrumentation instrumentation, boolean on) throws IOException {
+
+ String command = " cmd notification " + (on ? "allow_dnd " : "disallow_dnd ") + packageName;
+
+ runCommand(command, instrumentation);
+
+ NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+ Assert.assertEquals("Notification Policy Access Grant is " +
+ nm.isNotificationPolicyAccessGranted() + " not " + on, on,
+ nm.isNotificationPolicyAccessGranted());
+ }
+
+ private void runCommand(String command, Instrumentation instrumentation) throws IOException {
+ UiAutomation uiAutomation = instrumentation.getUiAutomation();
+ // Execute command
+ try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
+ Assert.assertNotNull("Failed to execute shell command: " + command, fd);
+ // Wait for the command to finish by reading until EOF
+ try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
+ byte[] buffer = new byte[4096];
+ while (in.read(buffer) > 0) {}
+ } catch (IOException e) {
+ throw new IOException("Could not read stdout of command: " + command, e);
+ }
+ } finally {
+ uiAutomation.destroy();
+ }
+ }
+
+ private void pollForSubscribe(PollableConditionProviderService service) throws Exception {
+ int tries = 30;
+ int delayMs = 200;
+
+ while (tries-- > 0 && !service.subscribed) {
+ try {
+ Thread.sleep(delayMs);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (!service.subscribed) {
+ Log.d(TAG, "not subscribed");
+ throw new Exception("Service never got onSubscribe()");
+ }
+ }
+
+ private void pollForConnection(Class<? extends PollableConditionProviderService> service,
+ boolean waitForConnection) throws Exception {
+ int tries = 100;
+ int delayMs = 200;
+
+ PollableConditionProviderService instance =
+ (PollableConditionProviderService) service.getMethod("getInstance").invoke(null);
+
+ while (tries-- > 0 && (waitForConnection ? instance == null : instance != null)) {
+ try {
+ Thread.sleep(delayMs);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ instance = (PollableConditionProviderService) service.getMethod("getInstance")
+ .invoke(null);
+ }
+
+ if (waitForConnection && instance == null) {
+ Log.d(TAG, service.getName() + " not bound");
+ throw new Exception("CPS never bound");
+ } else if (!waitForConnection && instance != null) {
+ Log.d(TAG, service.getName() + " still bound");
+ throw new Exception("CPS still bound");
+ } else {
+ Log.d(TAG, service.getName() + " has a correct bind state");
+ }
+ }
+}
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java
new file mode 100644
index 0000000..72d5d3e
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.notification.legacy.cts;
+
+import android.content.ComponentName;
+import android.service.notification.Condition;
+
+public class LegacyConditionProviderService extends PollableConditionProviderService {
+ private static PollableConditionProviderService sInstance = null;
+
+ public static ComponentName getId() {
+ return new ComponentName(LegacyConditionProviderService.class.getPackage().getName(),
+ LegacyConditionProviderService.class.getName());
+ }
+
+ public static PollableConditionProviderService getInstance() {
+ return sInstance;
+ }
+
+ @Override
+ public void onConnected() {
+ super.onConnected();
+ sInstance = this;
+ }
+
+ @Override
+ public void onDestroy() {
+ sInstance = null;
+ super.onDestroy();
+ }
+
+ public void toggleDND(boolean on) {
+ notifyCondition(
+ new Condition(conditionId, "", on ? Condition.STATE_TRUE : Condition.STATE_FALSE));
+ }
+}
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
index 69103c8..528d66f 100644
--- a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
@@ -46,6 +46,7 @@
import junit.framework.Assert;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -79,6 +80,12 @@
mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
}
+ @After
+ public void tearDown() throws Exception {
+ toggleListenerAccess(MockNotificationListener.getId(),
+ InstrumentationRegistry.getInstrumentation(), false);
+ }
+
@Test
public void testPrePCannotToggleAlarmsAndMediaTest() throws Exception {
if (mActivityManager.isLowRamDevice()) {
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java
new file mode 100644
index 0000000..226c96f
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.notification.legacy.cts;
+
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.util.Log;
+
+public abstract class PollableConditionProviderService extends ConditionProviderService {
+ final static String TAG = "CtsCps";
+
+ boolean isConnected;
+ boolean subscribed;
+ Uri conditionId;
+
+ @Override
+ public void onConnected() {
+ Log.d(TAG, getClass().getName() + " Connected");
+ isConnected = true;
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(TAG, getClass().getName() + " Destroyed");
+ isConnected = false;
+ super.onDestroy();
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ Log.d(TAG, getClass().getName() + " got subscribe");
+ subscribed = true;
+ this.conditionId = conditionId;
+ notifyCondition(new Condition(conditionId, "", Condition.STATE_TRUE));
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ Log.d(TAG, getClass().getName() + " got unsubscribe");
+ subscribed = false;
+ this.conditionId = null;
+ }
+}
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java
new file mode 100644
index 0000000..2310a30
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.notification.legacy.cts;
+
+import android.content.ComponentName;
+
+public class SecondaryConditionProviderService extends PollableConditionProviderService {
+ private static PollableConditionProviderService sInstance = null;
+
+ public static ComponentName getId() {
+ return new ComponentName(SecondaryConditionProviderService.class.getPackage().getName(),
+ SecondaryConditionProviderService.class.getName());
+ }
+
+ public static PollableConditionProviderService getInstance() {
+ return sInstance;
+ }
+
+ @Override
+ public void onConnected() {
+ super.onConnected();
+ sInstance = this;
+ }
+
+ @Override
+ public void onDestroy() {
+ sInstance = null;
+ super.onDestroy();
+ }
+
+}
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java
index 1caed6f..6b484bd 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java
@@ -16,7 +16,11 @@
package android.preference2.cts;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static org.junit.Assume.assumeFalse;
+
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
@@ -40,6 +44,9 @@
@Before
public void setup() {
+ PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+ // Ignore this test on Leanback since Leanback doesn't support portrait orientation
+ assumeFalse(pm.hasSystemFeature(FEATURE_LEANBACK));
mTestUtils = new TestUtils();
}
diff --git a/tests/tests/security/res/raw/bug_110435401.mid b/tests/tests/security/res/raw/bug_110435401.mid
new file mode 100644
index 0000000..184ab1f
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_110435401.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_65484460.mp4 b/tests/tests/security/res/raw/bug_65484460.mp4
new file mode 100644
index 0000000..13b37e9
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_65484460.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_68664359.mid b/tests/tests/security/res/raw/bug_68664359.mid
new file mode 100644
index 0000000..f816d82
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_68664359.mid
@@ -0,0 +1 @@
+DK:@~kkkkk
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/cve_2016_3879.mp3 b/tests/tests/security/res/raw/cve_2016_3879.mp3
new file mode 100644
index 0000000..23ca4c3
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2016_3879.mp3
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_18155.mp4 b/tests/tests/security/res/raw/cve_2017_18155.mp4
new file mode 100644
index 0000000..5765dbb
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_18155.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_9423.mp4 b/tests/tests/security/res/raw/cve_2018_9423.mp4
new file mode 100755
index 0000000..08e2387
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_9423.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
new file mode 100644
index 0000000..6a4990f
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import org.junit.Test;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.platform.test.annotations.SecurityTest;
+import android.test.AndroidTestCase;
+
+@SecurityTest
+public class BluetoothIntentsTest extends AndroidTestCase {
+ /**
+ * b/35258579
+ */
+ @SecurityTest
+ public void testAcceptIntent() {
+ genericIntentTest("ACCEPT");
+ }
+
+ /**
+ * b/35258579
+ */
+ @SecurityTest
+ public void testDeclineIntent() {
+ genericIntentTest("DECLINE");
+ }
+
+ private static final String prefix = "android.btopp.intent.action.";
+ private void genericIntentTest(String action) throws SecurityException {
+ try {
+ Intent should_be_protected_broadcast = new Intent();
+ should_be_protected_broadcast.setComponent(
+ new ComponentName("com.android.bluetooth",
+ "com.android.bluetooth.opp.BluetoothOppReceiver"));
+ should_be_protected_broadcast.setAction(prefix + action);
+ mContext.sendBroadcast(should_be_protected_broadcast);
+ }
+ catch (SecurityException e) {
+ return;
+ }
+
+ throw new SecurityException("An " + prefix + action +
+ " intent should not be broadcastable except by the system (declare " +
+ " as protected-broadcast in manifest)");
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 4e128bc..559d01a 100755
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -827,6 +827,16 @@
***********************************************************/
@SecurityTest
+ public void testStagefright_bug_68664359() throws Exception {
+ doStagefrightTest(R.raw.bug_68664359, 60000);
+ }
+
+ @SecurityTest
+ public void testStagefright_bug_110435401() throws Exception {
+ doStagefrightTest(R.raw.bug_110435401, 60000);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2017_0474() throws Exception {
doStagefrightTest(R.raw.cve_2017_0474, 120000);
}
@@ -919,6 +929,26 @@
doStagefrightTest(R.raw.cve_2016_6699);
}
+ @SecurityTest
+ public void testStagefright_bug_65484460() throws Exception {
+ doStagefrightTest(R.raw.bug_65484460);
+ }
+
+ @SecurityTest
+ public void testStagefright_cve_2017_18155() throws Exception {
+ doStagefrightTest(R.raw.cve_2017_18155);
+ }
+
+ @SecurityTest
+ public void testStagefright_cve_2018_9423() throws Exception {
+ doStagefrightTest(R.raw.cve_2018_9423);
+ }
+
+ @SecurityTest
+ public void testStagefright_cve_2016_3879() throws Exception {
+ doStagefrightTest(R.raw.cve_2016_3879);
+ }
+
private void doStagefrightTest(final int rid) throws Exception {
doStagefrightTestMediaPlayer(rid);
doStagefrightTestMediaCodec(rid);
diff --git a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
index d2cc04a..cd30602 100755
--- a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
+++ b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
@@ -23,6 +23,14 @@
<activity android:name="Launcher" android:enabled="true" android:exported="false">
</activity>
+
+ <activity-alias android:name="HomeActivity"
+ android:targetActivity="Launcher">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
</application>
</manifest>
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
index 904f0cf..f2b9fc4 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
@@ -129,6 +129,8 @@
assertExpectException(NullPointerException.class, "action must be set",
() -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
+ setCurrentCaller(getTestContext());
+
assertExpectException(
IllegalArgumentException.class, "Short label must be provided", () -> {
ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java
new file mode 100644
index 0000000..baa47b0
--- /dev/null
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.cts.shortcutmanager;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.runCommand;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ShortcutInfo;
+import android.platform.test.annotations.SecurityTest;
+import android.support.test.InstrumentationRegistry;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Assume;
+
+/**
+ * CTS for b/109824443.
+ */
+@SmallTest
+@SecurityTest
+public class ShortcutManagerFakingPublisherTest extends ShortcutManagerCtsTestsBase {
+ private static final String ANOTHER_PACKAGE =
+ "android.content.pm.cts.shortcutmanager.packages.package4";
+
+ private static final ComponentName ANOTHER_HOME_ACTIVITY = new ComponentName(
+ ANOTHER_PACKAGE, "android.content.pm.cts.shortcutmanager.packages.HomeActivity");
+
+ private static final String INVALID_ID =
+ "[ShortcutManagerFakingPublisherTest.shortcut_that_should_not_be_created]";
+
+ @Override
+ protected String getOverrideConfig() {
+ return "reset_interval_sec=999999,"
+ + "max_updates_per_interval=999999,"
+ + "max_shortcuts=10"
+ + "max_icon_dimension_dp=96,"
+ + "max_icon_dimension_dp_lowram=96,"
+ + "icon_format=PNG,"
+ + "icon_quality=100";
+ }
+
+ public void testSpoofingPublisher() {
+ final Context myContext = getTestContext();
+ final Context anotherContext;
+ try {
+ anotherContext = getTestContext().createPackageContext(ANOTHER_PACKAGE, 0);
+ } catch (NameNotFoundException e) {
+ fail("Unable to create package context for " + ANOTHER_PACKAGE);
+ return;
+ }
+ final ShortcutInfo invalid = new ShortcutInfo.Builder(anotherContext, INVALID_ID)
+ .setShortLabel(INVALID_ID)
+ .setIntent(new Intent(Intent.ACTION_VIEW))
+ .setActivity(ANOTHER_HOME_ACTIVITY)
+ .build();
+
+ // Check set.
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("setDynamicShortcuts1", mPackageContext1, () -> {
+ getManager().setDynamicShortcuts(list(
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("setDynamicShortcuts2A", mPackageContext1, () -> {
+ getManager().setDynamicShortcuts(list(
+ invalid,
+ makeShortcut("s1", "title1")));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("setDynamicShortcuts2B", mPackageContext1, () -> {
+ getManager().setDynamicShortcuts(list(
+ makeShortcut("s1", "title1"),
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // Check add.
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("addDynamicShortcuts1", mPackageContext1, () -> {
+ getManager().addDynamicShortcuts(list(
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("addDynamicShortcuts2A", mPackageContext1, () -> {
+ getManager().addDynamicShortcuts(list(
+ invalid,
+ makeShortcut("s1", "title1")));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("addDynamicShortcuts2B", mPackageContext1, () -> {
+ getManager().addDynamicShortcuts(list(
+ makeShortcut("s1", "title1"),
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // Check update.
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("updateShortcuts1", mPackageContext1, () -> {
+ getManager().updateShortcuts(list(
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("updateShortcuts2A", mPackageContext1, () -> {
+ getManager().updateShortcuts(list(
+ invalid,
+ makeShortcut("s1", "title1")));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("updateShortcuts2B", mPackageContext1, () -> {
+ getManager().updateShortcuts(list(
+ makeShortcut("s1", "title1"),
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // requestPin (API26 and above)
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("requestPinShortcut", mPackageContext1, () -> {
+ getManager().requestPinShortcut(invalid, null);
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // createShortcutResultIntent (API26 and above)
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("createShortcutResultIntent", mPackageContext1, () -> {
+ getManager().createShortcutResultIntent(invalid);
+ });
+ assertInvalidShortcutNotCreated();
+ });
+ }
+
+ private void assertInvalidShortcutNotCreated() {
+ for (String s : runCommand(InstrumentationRegistry.getInstrumentation(),
+ "dumpsys shortcut")) {
+ assertFalse("dumpsys shortcut contained invalid ID", s.contains(INVALID_ID));
+ }
+ }
+
+ private void assertShortcutPackageMismatch(String method, Context callerContext, Runnable r) {
+ assertExpectException(
+ "Caller=" + callerContext.getPackageName() + ", method=" + method,
+ SecurityException.class, "Shortcut package name mismatch",
+ () -> runWithCaller(callerContext, () -> r.run())
+ );
+ }
+}