am 0744f81e: am 5bff7130: am 605ed8bd: am 740270dc: am 1ca6c54c: am 135b3967: am cbbfd900: am f82b9449: am 29de7b18: am 7988d7f8: am 83dd0cef: am 1d4ac0f9: Merge "Update Android CTS bandaid urls that use test_key1 to a new key" into jb-dev

* commit '0744f81e19ad40bdd73648adc5197c4a2d770321':
  Update Android CTS bandaid urls that use test_key1 to a new key
diff --git a/.gitignore b/.gitignore
index b8a343c..07a80d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@
 .project
 .cproject
 .classpath
+/bin
+.idea/*
+.idea/
diff --git a/CtsBuild.mk b/CtsBuild.mk
index 6e57086..dbe93c7 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -30,6 +30,12 @@
 # File indicating which tests should be blacklisted due to problems.
 CTS_EXPECTATIONS := cts/tests/expectations/knownfailures.txt
 
+# File indicating which tests should be blacklisted due to unsupported abi.
+CTS_UNSUPPORTED_ABIS := cts/tests/expectations/unsupportedabis.txt
+
+# Holds the target architecture to build for.
+CTS_TARGET_ARCH := $(TARGET_ARCH)
+
 # Functions to get the paths of the build outputs.
 
 define cts-get-lib-paths
@@ -41,7 +47,7 @@
 endef
 
 define cts-get-native-paths
-	$(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe))/$(exe))
+	$(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe),,,$(3))/$(exe)$(2))
 endef
 
 define cts-get-package-paths
@@ -51,3 +57,11 @@
 define cts-get-test-xmls
 	$(foreach name,$(1),$(CTS_TESTCASES_OUT)/$(name).xml)
 endef
+
+define cts-get-executable-paths
+	$(foreach executable,$(1),$(CTS_TESTCASES_OUT)/$(executable))
+endef
+
+define cts-get-deqp-test-xmls
+	$(foreach api,$(1),$(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(api).xml)
+endef
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 76b91a7..31dc2fd 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -13,50 +13,83 @@
 # limitations under the License.
 
 cts_security_apps_list := \
-	CtsAppAccessData \
-	CtsAppWithData \
-	CtsExternalStorageApp \
-	CtsInstrumentationAppDiffCert \
-	CtsPermissionDeclareApp \
-	CtsPermissionDeclareAppCompat \
-	CtsReadExternalStorageApp \
-	CtsSharedUidInstall \
-	CtsSharedUidInstallDiffCert \
-	CtsSimpleAppInstall \
-	CtsSimpleAppInstallDiffCert \
-	CtsTargetInstrumentationApp \
-	CtsUsePermissionDiffCert \
-	CtsWriteExternalStorageApp \
-	CtsMultiUserStorageApp
+    CtsAppAccessData \
+    CtsAppWithData \
+    CtsDocumentProvider \
+    CtsDocumentClient \
+    CtsExternalStorageApp \
+    CtsInstrumentationAppDiffCert \
+    CtsPermissionDeclareApp \
+    CtsPermissionDeclareAppCompat \
+    CtsReadExternalStorageApp \
+    CtsSharedUidInstall \
+    CtsSharedUidInstallDiffCert \
+    CtsSimpleAppInstall \
+    CtsSimpleAppInstallDiffCert \
+    CtsSplitApp \
+    CtsSplitApp_x86 \
+    CtsSplitApp_x86_64 \
+    CtsSplitApp_armeabi-v7a \
+    CtsSplitApp_armeabi \
+    CtsSplitApp_arm64-v8a \
+    CtsSplitApp_mips64 \
+    CtsSplitApp_mips \
+    CtsSplitAppDiffVersion \
+    CtsSplitAppDiffCert \
+    CtsSplitAppFeature \
+    CtsTargetInstrumentationApp \
+    CtsUsePermissionDiffCert \
+    CtsWriteExternalStorageApp \
+    CtsMultiUserStorageApp
+
+cts_security_keysets_list := \
+    CtsKeySetTestApp \
+    CtsKeySetPermDefSigningA \
+    CtsKeySetPermDefSigningB\
+    CtsKeySetPermUseSigningA \
+    CtsKeySetPermUseSigningB \
+    CtsKeySetSigningAUpgradeA \
+    CtsKeySetSigningBUpgradeA \
+    CtsKeySetSigningAUpgradeAAndB \
+    CtsKeySetSigningAUpgradeAOrB \
+    CtsKeySetSigningAUpgradeB \
+    CtsKeySetSigningBUpgradeB \
+    CtsKeySetSigningAAndBUpgradeA \
+    CtsKeySetSigningAAndCUpgradeB \
+    CtsKeySetSigningAUpgradeNone
 
 cts_support_packages := \
     CtsAccelerationTestStubs \
+    CtsAppTestStubs \
     CtsDeviceAdmin \
     CtsDeviceOpenGl \
+    CtsDeviceOwnerApp \
     CtsDeviceTaskswitchingAppA \
     CtsDeviceTaskswitchingAppB \
     CtsDeviceTaskswitchingControl \
     CtsDeviceUi \
+    CtsIntentReceiverApp \
+    CtsIntentSenderApp \
+    CtsManagedProfileApp \
     CtsMonkeyApp \
     CtsMonkeyApp2 \
-    CtsSampleDeviceApp \
     CtsSomeAccessibilityServices \
-    CtsTestStubs \
     CtsThemeDeviceApp \
-    SignatureTest \
     TestDeviceSetup \
     CtsUiAutomatorApp \
     CtsUsbSerialTestApp \
-    $(cts_security_apps_list)
+    $(cts_security_apps_list) \
+    $(cts_security_keysets_list)
 
 cts_external_packages := \
-	com.replica.replicaisland
+    com.replica.replicaisland \
+    com.drawelements.deqp
 
 # Any APKs that need to be copied to the CTS distribution's testcases
 # directory but do not require an associated test package XML.
 CTS_TEST_CASE_LIST := \
-	$(cts_support_packages) \
-	$(cts_external_packages)
+    $(cts_support_packages) \
+    $(cts_external_packages)
 
 # Test packages that require an associated test package XML.
 cts_test_packages := \
@@ -88,9 +121,11 @@
     CtsGraphicsTestCases \
     CtsGraphics2TestCases \
     CtsHardwareTestCases \
+    CtsJobSchedulerDeviceTestCases \
     CtsJniTestCases \
     CtsKeystoreTestCases \
     CtsLocationTestCases \
+    CtsLocation2TestCases \
     CtsMediaStressTestCases \
     CtsMediaTestCases \
     CtsNativeOpenGLTestCases \
@@ -103,66 +138,103 @@
     CtsPermission2TestCases \
     CtsPreferenceTestCases \
     CtsPreference2TestCases \
+    CtsPrintTestCases \
     CtsProviderTestCases \
     CtsRenderscriptTestCases \
-    CtsRenderscriptGraphicsTestCases \
+    CtsRenderscriptLegacyTestCases \
     CtsRsCppTestCases \
-    CtsSampleDeviceTestCases \
     CtsSaxTestCases \
     CtsSecurityTestCases \
+    CtsSignatureTestCases \
     CtsSpeechTestCases \
     CtsTelephonyTestCases \
     CtsTextTestCases \
     CtsTextureViewTestCases \
     CtsThemeTestCases \
+    CtsTvTestCases \
+    CtsUiAutomationTestCases \
+    CtsUiRenderingTestCases \
+    CtsUsageStatsTestCases \
     CtsUtilTestCases \
     CtsViewTestCases \
     CtsWebkitTestCases \
+    CtsWebGLTestCases \
     CtsWidgetTestCases
 
 # All APKs that need to be scanned by the coverage utilities.
 CTS_COVERAGE_TEST_CASE_LIST := \
-	$(cts_support_packages) \
-	$(cts_test_packages)
+    $(cts_support_packages) \
+    $(cts_test_packages)
 
 # Host side only tests
 cts_host_libraries := \
     CtsAdbTests \
     CtsAppSecurityTests \
+    CtsDevicePolicyManagerTestCases \
     CtsHostJank \
     CtsHostUi \
     CtsMonkeyTestCases \
-    CtsSampleHostTestCases \
     CtsThemeHostTestCases \
+    CtsSecurityHostTestCases \
     CtsUsbTests
 
-# Native test executables that need to have associated test XMLs.
-cts_native_exes := \
-	NativeMediaTest_SL \
-	NativeMediaTest_XA \
-	bionic-unit-tests-cts \
+# List of native tests. For 32 bit targets, assumes that there will be
+# one test executable, and it will end in 32. For 64 bit targets, assumes
+# that there will be two executables, one that ends in 32 for the 32
+# bit executable and one that ends in 64 for the 64 bit executable.
+cts_native_tests := \
+    NativeMediaTest_SL \
+    NativeMediaTest_XA \
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
+cts_native_tests += bionic-unit-tests-cts
+endif
 
 cts_ui_tests := \
     CtsUiAutomatorTests
 
 cts_device_jars := \
-    CtsDeviceJank
+    CtsDeviceJank \
+    CtsPrintInstrument
+
+cts_device_executables := \
+    print-instrument
+
+cts_target_junit_tests := \
+    CtsJdwp
+
+cts_deqp_test_apis := \
+    gles3 \
+    gles31
 
 # All the files that will end up under the repository/testcases
 # directory of the final CTS distribution.
 CTS_TEST_CASES := $(call cts-get-lib-paths,$(cts_host_libraries)) \
     $(call cts-get-package-paths,$(cts_test_packages)) \
-    $(call cts-get-native-paths,$(cts_native_exes)) \
     $(call cts-get-ui-lib-paths,$(cts_ui_tests)) \
-    $(call cts-get-ui-lib-paths,$(cts_device_jars))
+    $(call cts-get-ui-lib-paths,$(cts_device_jars)) \
+    $(call cts-get-ui-lib-paths,$(cts_target_junit_tests)) \
+    $(call cts-get-executable-paths,$(cts_device_executables))
+
+# NOTE: If compiling on a 64 bit target, TARGET_2ND_ARCH will be non-empty
+# and will cause the function to expand to the secondary arch object
+# directory. If compiling on a 32 bit target, TARGET_2ND_ARCH will be
+# empty and will cause the function to expand to the primary arch object
+# directory.
+CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),32,$(TARGET_2ND_ARCH))
+
+ifeq ($(TARGET_IS_64_BIT),true)
+CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),64)
+endif
 
 # All the XMLs that will end up under the repository/testcases
 # and that need to be created before making the final CTS distribution.
 CTS_TEST_XMLS := $(call cts-get-test-xmls,$(cts_host_libraries)) \
     $(call cts-get-test-xmls,$(cts_test_packages)) \
-    $(call cts-get-test-xmls,$(cts_native_exes)) \
-    $(call cts-get-test-xmls,$(cts_ui_tests))
-
+    $(call cts-get-test-xmls,$(cts_native_tests)) \
+    $(call cts-get-test-xmls,$(cts_target_junit_tests)) \
+    $(call cts-get-test-xmls,$(cts_ui_tests)) \
+    $(call cts-get-deqp-test-xmls,$(cts_deqp_test_apis))
 
 # The following files will be placed in the tools directory of the CTS distribution
 CTS_TOOLS_LIST :=
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 397b39a..460b88a 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -21,9 +21,11 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := cts-sensors-tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-sensors-tests ctstestrunner
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 
@@ -41,7 +43,7 @@
 # Builds and launches CTS Verifier on a device.
 .PHONY: cts-verifier
 cts-verifier: CtsVerifier adb
-	adb install -r $(PRODUCT_OUT)/data/app/CtsVerifier.apk \
+	adb install -r $(PRODUCT_OUT)/data/app/CtsVerifier/CtsVerifier.apk \
 		&& adb shell "am start -n com.android.cts.verifier/.CtsVerifierActivity"
 
 #
@@ -59,6 +61,19 @@
 verifier-zip-name := $(verifier-dir-name).zip
 verifier-zip := $(cts-dir)/$(verifier-zip-name)
 
+# turned off sensor power tests in initial L release
+#$(PRODUCT_OUT)/data/app/CtsVerifier.apk $(verifier-zip): $(verifier-dir)/power/execute_power_tests.py
+#$(PRODUCT_OUT)/data/app/CtsVerifier.apk $(verifier-zip): $(verifier-dir)/power/power_monitors/monsoon.py
+
+# Copy the necessary host-side scripts to include in the zip file:
+#$(verifier-dir)/power/power_monitors/monsoon.py: cts/apps/CtsVerifier/assets/scripts/power_monitors/monsoon.py | $(ACP)
+#	$(hide) mkdir -p $(verifier-dir)/power/power_monitors
+#	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/power_monitors/*.py $(verifier-dir)/power/power_monitors/.
+#
+#$(verifier-dir)/power/execute_power_tests.py: cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py | $(ACP)
+#	$(hide) mkdir -p $(verifier-dir)/power
+#	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py $@
+
 cts : $(verifier-zip)
 ifeq ($(HOST_OS),linux)
 $(verifier-zip) : $(HOST_OUT)/bin/cts-usb-accessory
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 418742c..12ed5e5 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -17,11 +17,10 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
-      android:versionCode="1"
-      android:versionName="4.4W_r4">
+      android:versionCode="4"
+      android:versionName="5.0_r2">
 
-    <!-- Using 10+ for more complete NFC support... -->
-    <uses-sdk android:minSdkVersion="12"></uses-sdk>
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -34,6 +33,7 @@
     <uses-permission android:name="android.permission.FULLSCREEN" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.NFC" />
+    <uses-permission android:name="android.permission.VIBRATE" />
     <uses-feature android:name="android.hardware.camera.front"
                   android:required="false" />
     <uses-feature android:name="android.hardware.camera.autofocus"
@@ -43,8 +43,12 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
-
     <uses-feature android:name="android.hardware.usb.accessory" />
+    <uses-permission android:name="android.permission.CALL_PHONE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
     <!-- Needed by the Audio Quality Verifier to store the sound samples that will be mailed. -->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -58,6 +62,8 @@
         <meta-data android:name="com.google.android.backup.api_key"
                 android:value="AEdPqrEAAAAIbK6ldcOzoeRtQ1u1dFVJ1A7KetRhit-a1Xa82Q" />
 
+        <uses-library android:name="android.test.runner"/>
+
         <activity android:name=".TestListActivity" android:label="@string/app_name">
             <!--
                 TestListActivity will have the USB accessory Test in its test list, but it
@@ -88,6 +94,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.device_admin" />
         </activity>
 
         <!-- A generic activity for intent based tests -->
@@ -101,6 +109,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
         <receiver android:name=".admin.TestDeviceAdminReceiver"
@@ -117,6 +127,8 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.backup" />
         </activity>
 
         <activity android:name=".bluetooth.BluetoothTestActivity"
@@ -139,6 +151,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_control" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data android:name="test_excluded_features" android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".bluetooth.SecureServerActivity"
@@ -215,7 +228,14 @@
         <service android:name=".bluetooth.BleServerService"
                 android:label="ble_server_service_name" />
 
-        <activity android:name=".bluetooth.BleClientTestActivity"
+        <service android:name=".bluetooth.BleAdvertiserService"
+                android:label="@string/ble_advertiser_service_name" />
+
+        <service android:name=".bluetooth.BleScannerService"
+                android:label="@string/ble_scanner_service_name" />
+
+        <!-- TODO: Enable when test quality issues listed in b/18283088 is resolved -->
+        <!-- activity android:name=".bluetooth.BleClientTestActivity"
                 android:label="@string/ble_client_test_name"
                 android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
@@ -224,7 +244,9 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_le" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+        </activity -->
 
         <activity android:name=".bluetooth.BleClientConnectActivity"
                 android:label="@string/ble_client_connect_name"
@@ -314,7 +336,8 @@
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
         </activity>
 
-        <activity android:name=".bluetooth.BleServerStartActivity"
+        <!-- TODO: Enable when test quality issues listed in b/18283088 is resolved -->
+        <!-- activity android:name=".bluetooth.BleServerStartActivity"
                 android:label="@string/ble_server_start_name"
                 android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
@@ -323,6 +346,80 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_le" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+        </activity -->
+
+        <!-- TODO: Enable when test quality issues listed in b/18282549 is resolved -->
+        <!-- activity android:name=".bluetooth.BleScannerTestActivity"
+                android:label="@string/ble_scanner_test_name"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_le" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+        </activity -->
+
+        <activity android:name=".bluetooth.BleScannerPowerLevelActivity"
+                android:label="@string/ble_power_level_name"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_le" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleScannerTestActivity" />
+        </activity>
+
+        <activity android:name=".bluetooth.BleScannerHardwareScanFilterActivity"
+                android:label="@string/ble_scanner_scan_filter_name"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_le" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleScannerTestActivity" />
+        </activity>
+
+        <!-- TODO: Enable when test quality issues listed in b/18282549 is resolved -->
+        <!-- activity android:name=".bluetooth.BleAdvertiserTestActivity"
+                android:label="@string/ble_advertiser_test_name"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_le" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+         </activity -->
+
+        <activity android:name=".bluetooth.BleAdvertiserPowerLevelActivity"
+                android:label="@string/ble_power_level_name"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_le" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity" />
+        </activity>
+
+        <activity android:name=".bluetooth.BleAdvertiserHardwareScanFilterActivity"
+                android:label="@string/ble_advertiser_scan_filter_name"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_le" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity" />
         </activity>
 
         <activity android:name=".suid.SuidFilesActivity"
@@ -343,6 +440,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_security" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".streamquality.StreamingVideoActivity"
@@ -353,6 +452,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_streaming" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".streamquality.PlayVideoActivity"
@@ -452,6 +553,14 @@
                 android:label="@string/nfc_hce_conflicting_non_payment_emulator"
                 android:configChanges="keyboardHidden|orientation|screenSize" />
 
+        <activity android:name=".nfc.hce.ForegroundNonPaymentEmulatorActivity"
+                android:label="@string/nfc_hce_foreground_non_payment_emulator"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
+        <activity android:name=".nfc.hce.ForegroundPaymentEmulatorActivity"
+                android:label="@string/nfc_hce_foreground_payment_emulator"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
         <activity android:name=".nfc.hce.OffHostEmulatorActivity"
                 android:label="@string/nfc_hce_offhost_service_emulator"
                 android:configChanges="keyboardHidden|orientation|screenSize" />
@@ -468,6 +577,26 @@
                 android:label="@string/nfc_hce_tap_test_emulator"
                 android:configChanges="keyboardHidden|orientation|screenSize" />
 
+        <activity android:name=".nfc.hce.DynamicAidEmulatorActivity"
+                android:label="@string/nfc_hce_payment_dynamic_aids_emulator"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
+        <activity android:name=".nfc.hce.PrefixPaymentEmulatorActivity"
+                android:label="@string/nfc_hce_payment_prefix_aids_emulator"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
+        <activity android:name=".nfc.hce.PrefixPaymentEmulator2Activity"
+                android:label="@string/nfc_hce_payment_prefix_aids_emulator_2"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
+        <activity android:name=".nfc.hce.DualNonPaymentPrefixEmulatorActivity"
+                android:label="@string/nfc_hce_other_prefix_aids_emulator"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
+        <activity android:name=".nfc.hce.ConflictingNonPaymentPrefixEmulatorActivity"
+                android:label="@string/nfc_hce_other_conflicting_prefix_aids_emulator"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
         <!-- services used for testing NFC host-based card emulation -->
         <service android:name=".nfc.hce.PaymentService1" android:exported="true"
                  android:permission="android.permission.BIND_NFC_SERVICE"
@@ -533,20 +662,76 @@
             </intent-filter>
             <meta-data android:name="android.nfc.cardemulation.off_host_apdu_service" android:resource="@xml/offhost_aid_list"/>
         </service>
-
-        <activity android:name=".sensors.AccelerometerTestActivity" android:label="@string/snsr_accel_test"
-                android:screenOrientation="nosensor">
+        <service android:name=".nfc.hce.PaymentServiceDynamicAids" android:exported="true"
+                 android:permission="android.permission.BIND_NFC_SERVICE"
+                 android:enabled="false">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
-            <meta-data android:name="test_required_features" android:value="android.hardware.sensor.accelerometer" />
-        </activity>
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/payment_aid_list_1"/>
+        </service>
+        <service android:name=".nfc.hce.PrefixPaymentService1" android:exported="true"
+                 android:permission="android.permission.BIND_NFC_SERVICE"
+                 android:enabled="false">
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/payment_prefix_aid_list"/>
+        </service>
+        <service android:name=".nfc.hce.PrefixPaymentService2" android:exported="true"
+                 android:permission="android.permission.BIND_NFC_SERVICE"
+                 android:enabled="false">
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/payment_prefix_aid_list_2"/>
+        </service>
+        <service android:name=".nfc.hce.PrefixTransportService1" android:exported="true"
+                 android:permission="android.permission.BIND_NFC_SERVICE"
+                 android:enabled="false">
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/transport_prefix_aid_list_1"/>
+        </service>
+        <service android:name=".nfc.hce.PrefixTransportService2" android:exported="true"
+                 android:permission="android.permission.BIND_NFC_SERVICE"
+                 android:enabled="false">
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/transport_prefix_aid_list_2"/>
+        </service>
+        <service android:name=".nfc.hce.PrefixAccessService" android:exported="true"
+                 android:permission="android.permission.BIND_NFC_SERVICE"
+                 android:enabled="false">
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/access_prefix_aid_list"/>
+        </service>
+
+        <!--
+            A DeviceAdmin receiver for sensor tests, it allows sensor tests to turn off the screen.
+        -->
+        <receiver android:name=".sensors.helpers.SensorDeviceAdminReceiver"
+                android:label="@string/snsr_device_admin_receiver">
+            <meta-data android:name="android.app.device_admin"
+                       android:resource="@xml/sensor_device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
+            </intent-filter>
+        </receiver>
 
         <activity android:name=".sensors.AccelerometerMeasurementTestActivity"
                   android:label="@string/snsr_accel_m_test"
-                  android:screenOrientation="nosensor">
+                  android:screenOrientation="locked">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.cts.intent.category.MANUAL_TEST"/>
@@ -556,19 +741,9 @@
                        android:value="android.hardware.sensor.accelerometer"/>
         </activity>
 
-        <activity android:name=".sensors.GyroscopeTestActivity" android:label="@string/snsr_gyro_test"
-                android:screenOrientation="nosensor">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
-            </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
-            <meta-data android:name="test_required_features" android:value="android.hardware.sensor.gyroscope" />
-        </activity>
-
         <activity android:name=".sensors.GyroscopeMeasurementTestActivity"
                   android:label="@string/snsr_gyro_m_test"
-                  android:screenOrientation="nosensor">
+                  android:screenOrientation="locked">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.cts.intent.category.MANUAL_TEST"/>
@@ -590,10 +765,9 @@
                        android:value="android.hardware.sensor.heartrate" />
         </activity>
 
-        <!-- Disable the test until calibration routine is verified -->
-        <!--activity android:name=".sensors.MagneticFieldMeasurementTestActivity"
+        <activity android:name=".sensors.MagneticFieldMeasurementTestActivity"
                   android:label="@string/snsr_mag_m_test"
-                  android:screenOrientation="nosensor">
+                  android:screenOrientation="locked">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
@@ -601,8 +775,96 @@
             <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
             <meta-data android:name="test_required_features"
                        android:value="android.hardware.sensor.compass" />
+        </activity>
+
+        <!-- TODO: enable when a full set of verifications can be implemented -->
+        <!--activity android:name=".sensors.RotationVectorTestActivity"
+                  android:label="@string/snsr_rot_vec_test"
+                  android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.sensor.gyroscope" />
         </activity-->
 
+        <activity android:name=".sensors.BatchingTestActivity"
+                  android:label="@string/snsr_batch_test"
+                  android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.stepcounter:android.hardware.sensor.stepdetector:android.hardware.sensor.proximity:android.hardware.sensor.light" />
+        </activity>
+
+        <!-- TODO: enable when a more reliable way to identify time synchronization is available -->
+        <!--activity android:name=".sensors.SensorSynchronizationTestActivity"
+                  android:label="@string/snsr_synch_test"
+                  android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.sensor.gyroscope" />
+        </activity-->
+
+        <activity android:name=".sensors.SingleSensorTestsActivity"
+                  android:label="@string/snsr_single_sensor_tests"
+                  android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.compass:android.hardware.sensor.gyroscope:android.hardware.sensor.barometer" />
+        </activity>
+
+        <activity android:name=".sensors.SensorBatchingTestsActivity"
+                  android:label="@string/snsr_sensor_batching_tests"
+                  android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.compass:android.hardware.sensor.gyroscope:android.hardware.sensor.barometer" />
+        </activity>
+
+        <activity android:name=".sensors.SensorIntegrationTestsActivity"
+                  android:label="@string/snsr_sensor_integration_tests"
+                  android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.compass:android.hardware.sensor.gyroscope" />
+        </activity>
+
+        <activity android:name=".sensors.SensorTestActivity"
+                  android:label="@string/snsr_sensor_test"
+                  android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.stepcounter:android.hardware.sensor.stepdetector:android.hardware.sensor.heartrate:android.hardware.sensor.compass:android.hardware.sensor.ambient_temperature" />
+        </activity>
+
+        <!-- End sensor tests definitions -->
+
         <activity android:name=".location.LocationModeOffTestActivity"
                 android:label="@string/location_mode_off_test">
             <intent-filter>
@@ -610,6 +872,10 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".location.LocationModeHighAccuracyTestActivity"
                 android:label="@string/location_mode_high_accuracy_test">
@@ -618,6 +884,12 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.hardware.location.network:android.hardware.location.gps" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".location.LocationModeBatterySavingTestActivity"
                 android:label="@string/location_mode_battery_saving_test">
@@ -626,6 +898,11 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.network" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".location.LocationModeDeviceOnlyTestActivity"
                 android:label="@string/location_mode_device_only_test">
@@ -634,6 +911,11 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".camera.formats.CameraFormatsActivity"
@@ -735,8 +1017,22 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_hardware" />
             <meta-data android:name="test_required_features" android:value="android.hardware.usb.accessory" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
         </activity>
-
+<!-- Turned off Sensor Power Test in initial L release
+        <activity android:name=".sensors.SensorPowerTestActivity"
+                android:label="@string/sensor_power_test"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback" />
+        </activity>
+-->
         <activity android:name=".p2p.P2pTestListActivity"
                 android:label="@string/p2p_test"
                 android:configChanges="keyboardHidden|orientation|screenSize">
@@ -748,7 +1044,7 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.wifi.direct" />
         </activity>
 
-        <activity android:name=".nls.NotificationListenerVerifierActivity"
+        <activity android:name=".notifications.NotificationListenerVerifierActivity"
                 android:label="@string/nls_test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -757,7 +1053,16 @@
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
         </activity>
 
-        <service android:name=".nls.MockListener"
+        <activity android:name=".notifications.NotificationAttentionManagementVerifierActivity"
+                android:label="@string/attention_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+        </activity>
+
+        <service android:name=".notifications.MockListener"
                  android:exported="true"
                  android:label="@string/nls_service_name"
                  android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
@@ -766,7 +1071,7 @@
             </intent-filter>
         </service>
 
-        <service  android:name=".nls.NotificationListenerVerifierActivity$DismissService"/>
+        <service  android:name=".notifications.NotificationListenerVerifierActivity$DismissService"/>
         <activity android:name=".security.CAInstallNotificationVerifierActivity"
                 android:label="@string/cacert_test">
             <intent-filter>
@@ -774,6 +1079,12 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".security.CANotifyOnBootActivity"
                 android:label="@string/caboot_test">
@@ -782,6 +1093,12 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".p2p.GoNegRequesterTestListActivity"
@@ -825,17 +1142,19 @@
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
             </intent-filter>
         </activity-alias>
 
-        <activity android:name=".sample.SampleTestActivity"
+        <!-- remove comment from the next activity to see the sample test surfacing in the app -->
+        <!-- activity android:name=".sample.SampleTestActivity"
                   android:label="@string/sample_framework_test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_other" />
-        </activity>
+        </activity -->
 
         <activity android:name=".widget.WidgetTestActivity"
                 android:label="@string/widget_framework_test">
@@ -844,6 +1163,10 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_other" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.app_widgets" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".deskclock.DeskClockTestsActivity"
@@ -853,6 +1176,43 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_deskclock" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
+        </activity>
+
+<!-- TODO: enable when not requiring to tap the screen and timeouts are tuned -->
+<!-- Removed from initial L release
+
+        <activity
+                android:name="com.android.cts.verifier.sensors.StepCounterTestActivity"
+                android:label="@string/snsr_step_counter_test"
+                android:screenOrientation="nosensor" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback" />
+        </activity>
+-->
+        <activity
+            android:name="com.android.cts.verifier.sensors.SignificantMotionTestActivity"
+            android:label="@string/snsr_significant_motion_test"
+            android:screenOrientation="nosensor" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+
+            <meta-data
+                android:name="test_category"
+                android:value="@string/test_category_sensors" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.sensor.accelerometer" />
         </activity>
 
         <receiver android:name=".widget.WidgetCtsProvider">
@@ -869,6 +1229,166 @@
             android:permission="android.permission.BIND_REMOTEVIEWS"
             android:exported="false" />
 
-   </application>
+        <activity android:name=".projection.cube.ProjectionCubeActivity"
+                  android:label="@string/pca_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.faketouch" />
+        </activity>
+
+        <activity android:name=".projection.widgets.ProjectionWidgetActivity"
+                  android:label="@string/pwa_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.faketouch" />
+        </activity>
+
+        <activity android:name=".projection.list.ProjectionListActivity"
+                  android:label="@string/pla_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback" />
+        </activity>
+
+        <activity android:name=".projection.video.ProjectionVideoActivity"
+                  android:label="@string/pva_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
+        </activity>
+
+        <activity android:name=".projection.touch.ProjectionTouchActivity"
+                  android:label="@string/pta_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.faketouch" />
+        </activity>
+
+
+        <activity android:name=".projection.offscreen.ProjectionOffscreenActivity"
+                  android:label="@string/poa_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback" />
+        </activity>
+
+        <service android:name=".projection.ProjectionService"
+                 android:label="@string/projection_service_name"
+                 android:process=":projectionservice" />
+
+        <activity android:name=".managedprovisioning.DeviceOwnerTestActivity"
+                android:label="@string/provisioning_device_owner">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
+            <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
+        </activity>
+
+
+        <!-- TODO: enable when the test can be executed without leaving marks -->
+        <!-- activity android:name=".managedprovisioning.ByodFlowTestActivity"
+                android:launchMode="singleTask"
+                android:label="@string/provisioning_byod">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_STATUS" />
+                <category android:name="android.intent.category.DEFAULT"></category>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
+            <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
+        </activity-->
+
+        <activity android:name=".managedprovisioning.ByodHelperActivity">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_QUERY" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_REMOVE" />
+                <category android:name="android.intent.category.DEFAULT"></category>
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".managedprovisioning.CrossProfileTestActivity">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE" />
+                <category android:name="android.intent.category.DEFAULT"></category>
+            </intent-filter>
+        </activity>
+
+        <receiver android:name=".managedprovisioning.DeviceAdminTestReceiver"
+                android:label="@string/provisioning_byod_device_admin"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                       android:resource="@xml/device_admin_byod" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE"/>
+            </intent-filter>
+        </receiver>
+
+        <activity android:name=".jobscheduler.IdleConstraintTestActivity" android:label="@string/js_idle_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_jobscheduler" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
+        </activity>
+
+        <activity android:name=".jobscheduler.ChargingConstraintTestActivity" android:label="@string/js_charging_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_jobscheduler" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
+        </activity>
+
+        <activity android:name=".jobscheduler.ConnectivityConstraintTestActivity" android:label="@string/js_connectivity_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_jobscheduler" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
+        </activity>
+
+        <service android:name=".jobscheduler.MockJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE"/>
+
+    </application>
 
 </manifest>
diff --git a/apps/CtsVerifier/assets/scripts/execute_power_tests.py b/apps/CtsVerifier/assets/scripts/execute_power_tests.py
new file mode 100755
index 0000000..d1c2dac
--- /dev/null
+++ b/apps/CtsVerifier/assets/scripts/execute_power_tests.py
@@ -0,0 +1,585 @@
+#!/usr/bin/python
+
+# Copyright (C) 2014 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.
+
+import logging
+import os.path
+import select
+import sys
+import time
+import collections
+import socket
+import gflags as flags  # http://code.google.com/p/python-gflags/
+import pkgutil
+import threading
+import Queue
+
+# queue to signal thread to exit
+signal_exit_q = Queue.Queue()
+signal_abort = Queue.Queue()
+
+# let this script know about the power monitor implementations
+sys.path = [os.path.basename(__file__)] + sys.path
+available_monitors = [name for _, name, _ in pkgutil.iter_modules(
+    [os.path.join(os.path.dirname(__file__),'power_monitors')]) if not name.startswith('_')]
+
+APK = os.path.join( os.path.dirname(__file__), '..', "CtsVerifier.apk")
+
+FLAGS = flags.FLAGS
+
+# whether to use a strict delay to ensure screen is off, or attempt to use power measurements
+USE_STRICT_DELAY = False
+if USE_STRICT_DELAY:
+    DELAY_SCREEN_OFF = 30.0
+else:
+    DELAY_SCREEN_OFF = 2.0
+
+# whether to log data collected to a file for each sensor run:
+LOG_DATA_TO_FILE = True
+
+logging.getLogger().setLevel(logging.ERROR)
+
+def do_import(name):
+    """import a module by name dynamically"""
+    mod = __import__(name)
+    components = name.split('.')
+    for comp in components[1:]:
+        mod = getattr(mod, comp)
+    return mod
+
+
+class PowerTest:
+    """Class to run a suite of power tests"""
+
+    # Thresholds for max allowed power usage per sensor tested
+    MAX_ACCEL_POWER = 0.08  # Amps
+    MAX_MAG_POWER = 0.08  # Amps
+    MAX_GYRO_POWER = 0.08  # Amps
+    MAX_SIGMO_POWER = 0.08 # Amps
+    MAX_STEP_COUNTER_POWER = 0.08 # Amps
+    MAX_STEP_DETECTOR_POWER = 0.08 # Amps
+
+
+    PORT = 0  # any available port
+    DOMAIN_NAME = "/android/cts/powertest"
+    SAMPLE_COUNT_NOMINAL = 1000
+    RATE_NOMINAL = 100
+
+    REQUEST_EXTERNAL_STORAGE = "EXTERNAL STORAGE?"
+    REQUEST_EXIT = "EXIT"
+    REQUEST_RAISE = "RAISE %s %s"
+    REQUEST_USER_RESPONSE = "USER RESPONSE %s"
+    REQUEST_SET_TEST_RESULT = "SET TEST RESULT %s %s %s"
+    REQUEST_SENSOR_SWITCH = "SENSOR %s %s"
+    REQUEST_SENSOR_AVAILABILITY = "SENSOR? %s"
+    REQUEST_SCREEN_OFF = "SCREEN OFF"
+    REQUEST_SHOW_MESSAGE = "MESSAGE %s"
+
+
+    def __init__(self):
+        power_monitors = do_import("power_monitors.%s" % FLAGS.power_monitor)
+        testid = time.strftime("%d_%m_%Y__%H__%M_%S")
+        self._power_monitor = power_monitors.Power_Monitor(log_file_id = testid)
+        print ("Establishing connection to device...")
+        self.setUsbEnabled(True)
+        status = self._power_monitor.GetStatus()
+        self._native_hz = status["sampleRate"] * 1000
+        self._current_test = "None"
+        self._external_storage = self.executeOnDevice(PowerTest.REQUEST_EXTERNAL_STORAGE,
+                                                      reportErrors=True)
+
+    def __del__(self):
+        self.finalize()
+
+    def finalize(self):
+        """To be called upon termination of host connection to device"""
+        if PowerTest.PORT > 0:
+            # tell device side to exit connection loop, and remove the forwarding connection
+            self.executeOnDevice(PowerTest.REQUEST_EXIT, reportErrors=False)
+            self.executeLocal("adb forward --remove tcp:%d" % PowerTest.PORT)
+        PowerTest.PORT = 0
+        if self._power_monitor:
+            self._power_monitor.Close()
+            self._power_monitor = None
+
+    def _send(self, msg, report_errors=True):
+        """Connect to the device, send the given command, and then disconnect"""
+        if PowerTest.PORT == 0:
+            # on first attempt to send a command, connect to device via any open port number,
+            # forwarding that port to a local socket on the device via adb
+            logging.debug("Seeking port for communication...")
+            # discover an open port
+            dummysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            dummysocket.bind(("localhost", 0))
+            (_, PowerTest.PORT) = dummysocket.getsockname()
+            dummysocket.close()
+            assert(PowerTest.PORT > 0)
+            status = self.executeLocal("adb forward tcp:%d localabstract:%s" %
+                    (PowerTest.PORT, PowerTest.DOMAIN_NAME))
+            if report_errors:
+                self.reportErrorIf(status != 0, msg="Unable to forward requests to client over adb")
+            logging.info("Forwarding requests over local port %d" % PowerTest.PORT)
+
+        link = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+        try:
+            logging.debug("Connecting to device...")
+            link.connect (("localhost", PowerTest.PORT))
+            logging.debug("Connected.")
+        except:
+            if report_errors:
+                self.reportErrorIf(True, msg="Unable to communicate with device: connection refused")
+        logging.debug("Sending '%s'" % msg)
+        link.sendall(msg)
+        logging.debug("Getting response...")
+        response = link.recv(4096)
+        logging.debug("Got response '%s'" % response)
+        link.close()
+        return response
+
+    def queryDevice(self, query):
+        """Post a yes/no query to the device, return True upon successful query, False otherwise"""
+        logging.info("Querying device with '%s'" % query)
+        return self._send(query) == "OK"
+
+    # TODO: abstract device communication (and string commands) into its own class
+    def executeOnDevice(self, cmd , reportErrors=True):
+        """Execute a (string) command on the remote device"""
+        return self._send(cmd , reportErrors)
+
+    def executeLocal(self, cmd, check_status=True):
+        """execute a shell command locally (on the host)"""
+        from subprocess import call
+        status = call(cmd.split(' '))
+        if status != 0 and check_status:
+            logging.error("Failed to execute \"%s\"" % cmd)
+        else:
+            logging.debug("Executed \"%s\"" % cmd)
+        return status
+
+    def reportErrorIf(self, condition, msg):
+        """Report an error condition to the device if condition is True.
+        Will raise an exception on the device if condition is True"""
+        if condition:
+            try:
+                logging.error("Exiting on error: %s" % msg)
+                self.executeOnDevice(PowerTest.REQUEST_RAISE % (self._current_test, msg), False)
+            except:
+
+                logging.error("Unable to communicate with device to report error: %s" % msg)
+                self.finalize()
+                sys.exit(msg)
+            raise Exception(msg)
+
+    def setUsbEnabled(self, enabled, verbose=True):
+        if enabled:
+            val = 1
+        else:
+            val = 0
+        self._power_monitor.SetUsbPassthrough(val)
+        tries = 0
+
+        # Sometimes command won't go through first time, particularly if immediately after a data
+        # collection, so allow for retries
+        status = self._power_monitor.GetStatus()
+        while status is None and tries < 5:
+            tries += 1
+            time.sleep(2.0)
+            logging.error("Retrying get status call...")
+            self._power_monitor.StopDataCollection()
+            self._power_monitor.SetUsbPassthrough(val)
+            status = self._power_monitor.GetStatus()
+
+        if enabled:
+            if verbose: print("...USB enabled, waiting for device")
+            self.executeLocal ("adb wait-for-device")
+            if verbose: print("...device online")
+        else:
+            if verbose: logging.info("...USB disabled")
+        # re-establish port forwarding
+        if enabled and PowerTest.PORT > 0:
+            status = self.executeLocal("adb forward tcp:%d localabstract:%s" %
+                                       (PowerTest.PORT, PowerTest.DOMAIN_NAME))
+            self.reportErrorIf(status != 0, msg="Unable to forward requests to client over adb")
+
+    def waitForScreenOff(self):
+        # disconnect of USB will cause screen to go on, so must wait (1 second more than screen off
+        # timeout)
+        if USE_STRICT_DELAY:
+            time.sleep(DELAY_SCREEN_OFF)
+            return
+
+        # need at least 100 sequential clean low-power measurements to know screen is off
+        THRESHOLD_COUNT_LOW_POWER = 100
+        CURRENT_LOW_POWER_THRESHOLD = 0.060  # Amps
+        TIMEOUT_SCREEN_OFF = 30 # this many tries at most
+        count_good = 0
+        tries = 0
+        print("Waiting for screen off and application processor in suspend mode...")
+        while count_good < THRESHOLD_COUNT_LOW_POWER:
+            measurements = self.collectMeasurements(THRESHOLD_COUNT_LOW_POWER,
+                                                      PowerTest.RATE_NOMINAL,
+                                                      ensure_screen_off=False,
+                                                      verbose=False)
+            count_good = len([m for m in measurements
+                               if m < CURRENT_LOW_POWER_THRESHOLD])
+            tries += 1
+            if count_good < THRESHOLD_COUNT_LOW_POWER and measurements:
+                print("Current usage: %.2f mAmps. Device is probably not in suspend mode.   Waiting..." %
+                      (1000.0*(sum(measurements)/len(measurements))))
+            if tries >= TIMEOUT_SCREEN_OFF:
+                # TODO: dump the state of sensor service to identify if there are features using sensors
+                self.reportErrorIf(tries>=TIMEOUT_SCREEN_OFF,
+                    msg="Unable to determine application processor suspend mode status.")
+                break
+        if DELAY_SCREEN_OFF:
+            # add additional delay time if necessary
+            time.sleep(DELAY_SCREEN_OFF)
+        print("...Screen off and device in suspend mode.")
+
+    def collectMeasurements(self, measurementCount, rate , ensure_screen_off=True, verbose=True,
+                             plot_data = False):
+        assert(measurementCount > 0)
+        decimate_by = self._native_hz / rate  or 1
+        if ensure_screen_off:
+            self.waitForScreenOff()
+            print ("Taking measurements...")
+        self._power_monitor.StartDataCollection()
+        sub_measurements = []
+        measurements = []
+        tries = 0
+        if verbose: print("")
+        try:
+            while len(measurements) < measurementCount and tries < 5:
+                if tries:
+                    self._power_monitor.StopDataCollection()
+                    self._power_monitor.StartDataCollection()
+                    time.sleep(1.0)
+                tries += 1
+                additional = self._power_monitor.CollectData()
+                if additional is not None:
+                    tries = 0
+                    sub_measurements.extend(additional)
+                    while len(sub_measurements) >= decimate_by:
+                        sub_avg = sum(sub_measurements) / len(sub_measurements)
+                        measurements.append(sub_avg)
+                        sub_measurements = sub_measurements[decimate_by:]
+                        if verbose:
+                            sys.stdout.write("\33[1A\33[2K")
+                            print ("MEASURED[%d]: %f" % (len(measurements),measurements[-1]))
+        finally:
+            self._power_monitor.StopDataCollection()
+
+        self.reportErrorIf(measurementCount > len(measurements),
+                            "Unable to collect all requested measurements")
+        return measurements
+
+    def request_user_acknowledgment(self, msg):
+        """Post message to user on screen and wait for acknowledgment"""
+        response = self.executeOnDevice(PowerTest.REQUEST_USER_RESPONSE % msg)
+        self.reportErrorIf(response != "OK", "Unable to request user acknowledgment")
+
+    def setTestResult (self, testname, condition, msg):
+        if condition is False:
+            val = "FAIL"
+        elif condition is True:
+            val = "PASS"
+        else:
+            val = condition
+        print ("Test %s : %s" % (testname, val))
+        response = self.executeOnDevice(PowerTest.REQUEST_SET_TEST_RESULT % (testname, val, msg))
+        self.reportErrorIf(response != "OK", "Unable to send test status to Verifier")
+
+    def setPowerOn(self, sensor, powered_on):
+        response = self.executeOnDevice(PowerTest.REQUEST_SENSOR_SWITCH %
+                                        ({True:"ON", False:"OFF"}[powered_on], sensor))
+        self.reportErrorIf(response == "ERR", "Unable to set sensor %s state" % sensor)
+        logging.info("Set %s %s" % (sensor, {True:"ON", False:"OFF"}[powered_on]))
+        return response
+
+    def runPowerTest(self, sensor, max_power_allowed, user_request = None):
+        if not signal_abort.empty():
+            sys.exit( signal_abort.get() )
+        self._current_test = "%s_Power_Test_While_%s" % (sensor,
+                                    {True:"Under_Motion", False:"Still"}[user_request is not None])
+        try:
+            print ("\n\n---------------------------------")
+            if user_request is not None:
+                print ("Running power test on %s under motion." % sensor)
+            else:
+                print ("Running power test on %s while device is still." % sensor)
+            print ("---------------------------------")
+            response = self.executeOnDevice(PowerTest.REQUEST_SENSOR_AVAILABILITY % sensor)
+            if response == "UNAVAILABLE":
+                self.setTestResult(self._current_test, condition="SKIPPED",
+                    msg="Sensor %s not available on this platform"%sensor)
+            self.setPowerOn("ALL", False)
+            if response == "UNAVAILABLE":
+                self.setTestResult(self._current_test, condition="SKIPPED",
+                                   msg="Sensor %s not available on this device"%sensor)
+                return
+
+            self.reportErrorIf(response != "OK", "Unable to set all sensor off")
+            if not signal_abort.empty():
+                sys.exit( signal_abort.get() )
+            self.executeOnDevice(PowerTest.REQUEST_SCREEN_OFF)
+            self.setUsbEnabled(False)
+            print("Collecting background measurements...")
+            measurements = self.collectMeasurements( PowerTest.SAMPLE_COUNT_NOMINAL,
+                                                     PowerTest.RATE_NOMINAL,
+                                                     plot_data = True)
+            if measurements and LOG_DATA_TO_FILE:
+                with open( "/tmp/cts-power-tests-%s-%s-background-data.log"%(sensor,
+                   {True:"Under_Motion", False:"Still"}[user_request is not None] ),'w') as f:
+                    for m in measurements:
+                        f.write( "%.4f\n"%m)
+            self.reportErrorIf(not measurements, "No background measurements could be taken")
+            backgnd = sum(measurements) / len(measurements)
+            self.setUsbEnabled(True)
+            self.setPowerOn(sensor, True)
+            if user_request is not None:
+                print("===========================================\n" +
+                      "==> Please follow the instructions presented on the device\n" +
+                      "==========================================="
+                     )
+                self.request_user_acknowledgment(user_request)
+            self.executeOnDevice(PowerTest.REQUEST_SCREEN_OFF)
+            self.setUsbEnabled(False)
+            self.reportErrorIf(response != "OK", "Unable to set sensor %s ON" % sensor)
+            print ("Collecting sensor %s measurements" % sensor)
+            measurements = self.collectMeasurements(PowerTest.SAMPLE_COUNT_NOMINAL,
+                                                    PowerTest.RATE_NOMINAL)
+
+            if measurements and LOG_DATA_TO_FILE:
+                with open( "/tmp/cts-power-tests-%s-%s-sensor-data.log"%(sensor,
+                   {True:"Under_Motion", False:"Still"}[user_request is not None] ),'w') as f:
+                    for m in measurements:
+                        f.write( "%.4f\n"%m)
+                    self.setUsbEnabled(True, verbose = False)
+                    print("Saving raw data files to device...")
+                    self.executeLocal("adb shell mkdir -p %s" % self._external_storage, False)
+                    self.executeLocal("adb push %s %s/." % (f.name, self._external_storage))
+                    self.setUsbEnabled(False, verbose = False)
+            self.reportErrorIf(not measurements, "No measurements could be taken for %s" % sensor)
+            avg = sum(measurements) / len(measurements)
+            squared = [(m-avg)*(m-avg) for m in measurements]
+
+            import math
+            stddev = math.sqrt(sum(squared)/len(squared))
+            current_diff = avg - backgnd
+            self.setUsbEnabled(True)
+            max_power = max(measurements) - avg
+            if current_diff <= max_power_allowed:
+                # TODO: fail the test of background > current
+                message = ("Draw is within limits. Current:%f Background:%f   Measured: %f Stddev: %f  Peak: %f")%\
+                             ( current_diff*1000.0, backgnd*1000.0, avg*1000.0, stddev*1000.0, max_power*1000.0)
+            else:
+                message = ("Draw is too high. Current:%f Background:%f   Measured: %f Stddev: %f  Peak: %f")%\
+                             ( current_diff*1000.0, backgnd*1000.0, avg*1000.0, stddev*1000.0, max_power*1000.0)
+            self.setTestResult( testname = self._current_test,
+                                condition = current_diff <= max_power_allowed,
+                                msg = message)
+            print("Result: "+message)
+        except:
+            import traceback
+            traceback.print_exc()
+            self.setTestResult(self._current_test, condition="FAIL",
+                               msg="Exception occurred during run of test.")
+
+
+    @staticmethod
+    def run_tests():
+        testrunner = None
+        try:
+            GENERIC_MOTION_REQUEST = "\n===> Please press Next and when the screen is off, keep " + \
+                "the device under motion with only tiny, slow movements until the screen turns " + \
+                "on again.\nPlease refrain from interacting with the screen or pressing any side " + \
+                "buttons while measurements are taken."
+            USER_STEPS_REQUEST = "\n===> Please press Next and when the screen is off, then move " + \
+                "the device to simulate step motion until the screen turns on again.\nPlease " + \
+                "refrain from interacting with the screen or pressing any side buttons while " + \
+                "measurements are taken."
+            testrunner = PowerTest()
+            testrunner.executeOnDevice(PowerTest.REQUEST_SHOW_MESSAGE % "Connected.  Running tests...")
+            testrunner.runPowerTest("SIGNIFICANT_MOTION", PowerTest.MAX_SIGMO_POWER, user_request = GENERIC_MOTION_REQUEST)
+            testrunner.runPowerTest("STEP_DETECTOR", PowerTest.MAX_STEP_DETECTOR_POWER, user_request = USER_STEPS_REQUEST)
+            testrunner.runPowerTest("STEP_COUNTER", PowerTest.MAX_STEP_COUNTER_POWER, user_request = USER_STEPS_REQUEST)
+            testrunner.runPowerTest("ACCELEROMETER", PowerTest.MAX_ACCEL_POWER, user_request = GENERIC_MOTION_REQUEST)
+            testrunner.runPowerTest("MAGNETIC_FIELD", PowerTest.MAX_MAG_POWER, user_request = GENERIC_MOTION_REQUEST)
+            testrunner.runPowerTest("GYROSCOPE", PowerTest.MAX_GYRO_POWER, user_request = GENERIC_MOTION_REQUEST)
+            testrunner.runPowerTest("ACCELEROMETER", PowerTest.MAX_ACCEL_POWER, user_request = None)
+            testrunner.runPowerTest("MAGNETIC_FIELD", PowerTest.MAX_MAG_POWER, user_request = None)
+            testrunner.runPowerTest("GYROSCOPE", PowerTest.MAX_GYRO_POWER, user_request = None)
+            testrunner.runPowerTest("SIGNIFICANT_MOTION", PowerTest.MAX_SIGMO_POWER, user_request = None)
+            testrunner.runPowerTest("STEP_DETECTOR", PowerTest.MAX_STEP_DETECTOR_POWER, user_request = None)
+            testrunner.runPowerTest("STEP_COUNTER", PowerTest.MAX_STEP_COUNTER_POWER, user_request = None)
+        except:
+            import traceback
+            traceback.print_exc()
+        finally:
+            signal_exit_q.put(0) # anything will signal thread to terminate
+            logging.info("TESTS COMPLETE")
+            if testrunner:
+                try:
+                    testrunner.finalize()
+                except socket.error:
+                    sys.exit("============================\nUnable to connect to device under " + \
+                             "test. Make sure the device is connected via the usb pass-through, " + \
+                             "the CtsVerifier app is running the SensorPowerTest on the device, " + \
+                             "and USB pass-through is enabled.\n===========================")
+
+
+def main(argv):
+  """ Simple command-line interface for a power test application."""
+  useful_flags = ["voltage", "status", "usbpassthrough",
+                  "samples", "current", "log", "power_monitor"]
+  if not [f for f in useful_flags if FLAGS.get(f, None) is not None]:
+    print __doc__.strip()
+    print FLAGS.MainModuleHelp()
+    return
+
+  if FLAGS.avg and FLAGS.avg < 0:
+    loggign.error("--avg must be greater than 0")
+    return
+
+  if FLAGS.voltage is not None:
+    if FLAGS.voltage > 5.5:
+        print("!!WARNING: Voltage higher than typical values!!!")
+    try:
+        response = raw_input("Voltage of %.3f requested.  Confirm this is correct (Y/N)"%FLAGS.voltage)
+        if response.upper() != "Y":
+            sys.exit("Aborting")
+    except:
+        sys.exit("Aborting.")
+
+  if not FLAGS.power_monitor:
+      sys.exit("You must specify a '--power_monitor' option to specify which power monitor type " + \
+               "you are using.\nOne of:\n  \n  ".join(available_monitors))
+  power_monitors = do_import('power_monitors.%s' % FLAGS.power_monitor)
+  try:
+      mon = power_monitors.Power_Monitor(device=FLAGS.device)
+  except:
+      import traceback
+      traceback.print_exc()
+      sys.exit("No power monitors found")
+
+  if FLAGS.voltage is not None:
+
+    if FLAGS.ramp is not None:
+      mon.RampVoltage(mon.start_voltage, FLAGS.voltage)
+    else:
+      mon.SetVoltage(FLAGS.voltage)
+
+  if FLAGS.current is not None:
+    mon.SetMaxCurrent(FLAGS.current)
+
+  if FLAGS.status:
+    items = sorted(mon.GetStatus().items())
+    print "\n".join(["%s: %s" % item for item in items])
+
+  if FLAGS.usbpassthrough:
+    if FLAGS.usbpassthrough == 'off':
+      mon.SetUsbPassthrough(0)
+    elif FLAGS.usbpassthrough == 'on':
+      mon.SetUsbPassthrough(1)
+    elif FLAGS.usbpassthrough == 'auto':
+      mon.SetUsbPassthrough(2)
+    else:
+      mon.Close()
+      sys.exit('bad pass-through flag: %s' % FLAGS.usbpassthrough)
+
+  if FLAGS.samples:
+    # Make sure state is normal
+    mon.StopDataCollection()
+    status = mon.GetStatus()
+    native_hz = status["sampleRate"] * 1000
+
+    # Collect and average samples as specified
+    mon.StartDataCollection()
+
+    # In case FLAGS.hz doesn't divide native_hz exactly, use this invariant:
+    # 'offset' = (consumed samples) * FLAGS.hz - (emitted samples) * native_hz
+    # This is the error accumulator in a variation of Bresenham's algorithm.
+    emitted = offset = 0
+    collected = []
+    history_deque = collections.deque()  # past n samples for rolling average
+
+    try:
+      last_flush = time.time()
+      while emitted < FLAGS.samples or FLAGS.samples == -1:
+        # The number of raw samples to consume before emitting the next output
+        need = (native_hz - offset + FLAGS.hz - 1) / FLAGS.hz
+        if need > len(collected):  # still need more input samples
+          samples = mon.CollectData()
+          if not samples: break
+          collected.extend(samples)
+        else:
+          # Have enough data, generate output samples.
+          # Adjust for consuming 'need' input samples.
+          offset += need * FLAGS.hz
+          while offset >= native_hz:  # maybe multiple, if FLAGS.hz > native_hz
+            this_sample = sum(collected[:need]) / need
+
+            if FLAGS.timestamp: print int(time.time()),
+
+            if FLAGS.avg:
+              history_deque.appendleft(this_sample)
+              if len(history_deque) > FLAGS.avg: history_deque.pop()
+              print "%f %f" % (this_sample,
+                               sum(history_deque) / len(history_deque))
+            else:
+              print "%f" % this_sample
+            sys.stdout.flush()
+
+            offset -= native_hz
+            emitted += 1  # adjust for emitting 1 output sample
+          collected = collected[need:]
+          now = time.time()
+          if now - last_flush >= 0.99:  # flush every second
+            sys.stdout.flush()
+            last_flush = now
+    except KeyboardInterrupt:
+      print("interrupted")
+      return 1
+    finally:
+      mon.Close()
+    return 0
+
+  if FLAGS.run:
+    if not FLAGS.power_monitor:
+        sys.exit("When running power tests, you must specify which type of power monitor to use" +
+                 " with '--power_monitor <type of power monitor>'")
+    PowerTest.run_tests()
+
+
+if __name__ == "__main__":
+    flags.DEFINE_boolean("status", None, "Print power meter status")
+    flags.DEFINE_integer("avg", None,
+                         "Also report average over last n data points")
+    flags.DEFINE_float("voltage", None, "Set output voltage (0 for off)")
+    flags.DEFINE_float("current", None, "Set max output current")
+    flags.DEFINE_string("usbpassthrough", None, "USB control (on, off, auto)")
+    flags.DEFINE_integer("samples", None, "Collect and print this many samples")
+    flags.DEFINE_integer("hz", 5000, "Print this many samples/sec")
+    flags.DEFINE_string("device", None,
+                        "Path to the device in /dev/... (ex:/dev/ttyACM1)")
+    flags.DEFINE_boolean("timestamp", None,
+                         "Also print integer (seconds) timestamp on each line")
+    flags.DEFINE_boolean("ramp", True, "Gradually increase voltage")
+    flags.DEFINE_boolean("log", False, "Log progress to a file or not")
+    flags.DEFINE_boolean("run", False, "Run the test suite for power")
+    flags.DEFINE_string("power_monitor", None, "Type of power monitor to use")
+    sys.exit(main(FLAGS(sys.argv)))
+
diff --git a/apps/CtsVerifier/assets/scripts/power_monitors/__init__.py b/apps/CtsVerifier/assets/scripts/power_monitors/__init__.py
new file mode 100644
index 0000000..cec4545
--- /dev/null
+++ b/apps/CtsVerifier/assets/scripts/power_monitors/__init__.py
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+
+# Copyright (C) 2014 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.
+#
+
+from abc import abstractmethod
+
+class Abstract_Power_Monitor(object):
+  """
+  Provides a simple interface to use the power meter.
+  The implementer should establish communications with the power monitor
+  on __init__:
+
+  monitor = <<Implementing Class>>(...)
+
+  Afterward, data can be collected multiple times via the
+  series of calls, for example:
+
+      montior.StartDataCollection()
+      data = True
+      while data is not None:
+          data = monitor.CollectData()
+          <<do-something-with-data>>
+      monitor.StopDataCollection()
+
+  On exit, Close should be called:
+
+      monitor.Close()
+
+  The method GetStatus() can be used to check voltage setting as well as
+  ensure status of the USB passthrough connection.
+  """
+
+  
+  
+  def __init__(self ):
+      pass  
+
+  @abstractmethod
+  def Close(self):
+      """Close the connection to the device, preventing
+      further interactions.  This should be called only
+      when the power monitor is no longer needed
+      (e.g. on exit)
+      """
+      pass
+
+  @abstractmethod
+  def GetStatus(self):
+    """ Requests and waits for status.  Returns status dictionary.
+    This should at a minimum contain entries for "usbPassthroughMode"
+    and "outputVoltageSetting" """
+    pass
+
+  @abstractmethod
+  def SetVoltage(self, v):
+    """ Set the output voltage, 0 to disable. """
+    pass
+
+  @abstractmethod
+  def SetMaxCurrent(self, i):
+    """Set the max output current."""
+    pass
+    
+  @abstractmethod
+  def SetUsbPassthrough(self, val):
+    """ Set the USB passthrough mode: 0 = off, 1 = on,  2 = auto. """
+    pass
+
+  @abstractmethod
+  def StartDataCollection(self):    
+    """ Tell the device to start collecting and sending measurement data. """
+    pass
+    
+  @abstractmethod
+  def StopDataCollection(self):
+    """ Tell the device to stop collecting measurement data. """
+    pass
+    
+  @abstractmethod
+  def CollectData(self, verbose = True):
+    """ Return some current samples.  Call StartDataCollection() first.
+    Returns None if no data available"""
+    pass
diff --git a/apps/CtsVerifier/assets/scripts/power_monitors/_dummy.py b/apps/CtsVerifier/assets/scripts/power_monitors/_dummy.py
new file mode 100644
index 0000000..16c2f3c
--- /dev/null
+++ b/apps/CtsVerifier/assets/scripts/power_monitors/_dummy.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+
+# Copyright (C) 2014 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.
+
+from . import Abstract_Power_Monitor
+
+class Power_Monitor(Abstract_Power_Monitor):
+  """
+  Dummy implementation for internal use only to test host-to-device
+  interactions without need for a real power monitor.  This is not
+  to be used in any way as part of CtsVerifier or CTS verification
+  activities in general.
+  """
+
+  
+  def __init__(self, device = None, wait = False, log_file_id = None ):
+      self._device = device
+      self._usbpassthroughmode = 1
+      self._voltage = 0.0
+      self._data_active = False
+      self._sequence = 0
+      
+  def __del__(self):
+      self.Close()
+
+  def Close(self):
+      pass
+    
+  @staticmethod
+  def Discover():
+      return ["dummy_monitor"]
+
+  def GetStatus(self):
+    """ Requests and waits for status.  Returns status dictionary. """
+    return {"usbPassthroughMode": self._usbpassthroughmode,
+            "sampleRate":1}
+
+
+  def RampVoltage(self, start, end):
+      self._voltage = end   
+
+  def SetVoltage(self, v):
+    """ Set the output voltage, 0 to disable. """
+    self._voltage = v
+
+  def SetMaxCurrent(self, i):
+    """Set the max output current."""
+    self._max_current = i
+    
+  def SetUsbPassthrough(self, val):
+    """ Set the USB passthrough mode: 0 = off, 1 = on,  2 = auto. """
+    self._usbpassthroughmode = val
+
+  def StartDataCollection(self):    
+    """ Tell the device to start collecting and sending measurement data. """
+    self._data_active = True
+    
+  def StopDataCollection(self):
+    """ Tell the device to stop collecting measurement data. """
+    self._data_active = False
+    
+  def CollectData(self, verbose = True):
+    """ Return some current samples.  Call StartDataCollection() first. """
+    #self.log("Collecting data ...", debug = True)
+    import random
+    if self._data_active:
+        base = [0.003, 0.003, 0.003, (self._sequence%4)*0.0005]
+        self._sequence += 1
+        values = [ random.gauss(base[(self._sequence-1)%4], 0.0005) for _ in range(100)]
+    else:
+        values = None
+    return values
diff --git a/apps/CtsVerifier/assets/scripts/power_monitors/monsoon.py b/apps/CtsVerifier/assets/scripts/power_monitors/monsoon.py
new file mode 100644
index 0000000..c02f113
--- /dev/null
+++ b/apps/CtsVerifier/assets/scripts/power_monitors/monsoon.py
@@ -0,0 +1,433 @@
+#!/usr/bin/python
+
+# Copyright (C) 2014 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.
+
+
+import fcntl
+import logging
+logging.getLogger().setLevel(logging.ERROR)
+
+import os.path
+import select
+import stat
+import struct
+import sys
+import time
+import collections
+import socket
+import glob
+import signal
+import serial           # http://pyserial.sourceforge.net/
+
+#Set to True if you want log output to go to screen:
+LOG_TO_SCREEN = False
+
+TIMEOUT_SERIAL = 1 #seconds
+
+#ignore SIG CONTINUE signals
+for signum in [signal.SIGCONT]:              
+  signal.signal(signum, signal.SIG_IGN)
+
+try:
+  from . import Abstract_Power_Monitor
+except:
+  sys.exit("You cannot run 'monsoon.py' directly.  Run 'execut_power_tests.py' instead.")
+  
+class Power_Monitor(Abstract_Power_Monitor):
+  """
+  Provides a simple class to use the power meter, e.g.
+  mon = monsoon.Power_Monitor()
+  mon.SetVoltage(3.7)
+  mon.StartDataCollection()
+  mydata = []
+  while len(mydata) < 1000:
+    mydata.extend(mon.CollectData())
+  mon.StopDataCollection()
+  """
+  _do_log = False
+
+  @staticmethod
+  def lock( device ):
+      tmpname = "/tmp/monsoon.%s.%s" % ( os.uname()[0],
+                                         os.path.basename(device))
+      lockfile = open(tmpname, "w")
+      try:  # use a lockfile to ensure exclusive access
+          fcntl.lockf(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
+          logging.debug("Locked device %s"%device)
+      except IOError as e:
+          self.log("device %s is in use" % dev)
+          sys.exit('device in use')
+      return lockfile
+  
+  def to_string(self):
+      return self._devicename
+  
+  def __init__(self, device = None, wait = False, log_file_id= None ):
+    """
+    Establish a connection to a Power_Monitor.
+    By default, opens the first available port, waiting if none are ready.
+    A particular port can be specified with "device".
+    With wait=0, IOError is thrown if a device is not immediately available.
+    """
+    self._lockfile = None
+    self._logfile = None
+    self.ser = None
+    for signum in [signal.SIGALRM, signal.SIGHUP, signal.SIGINT,
+                   signal.SIGILL, signal.SIGQUIT,
+                   signal.SIGTRAP,signal.SIGABRT, signal.SIGIOT, signal.SIGBUS,
+                   signal.SIGFPE, signal.SIGSEGV, signal.SIGUSR2, signal.SIGPIPE,
+                   signal.SIGTERM]:
+      signal.signal(signum, self.handle_signal)
+
+    self._coarse_ref = self._fine_ref = self._coarse_zero = self._fine_zero = 0
+    self._coarse_scale = self._fine_scale = 0
+    self._last_seq = 0
+    self.start_voltage = 0
+        
+    if device:
+      if isinstance( device, serial.Serial ):
+        self.ser = device
+        
+    else:
+        device_list = None
+        while not device_list:
+            device_list = Power_Monitor.Discover()
+            if not device_list and wait:
+                time.sleep(1.0)
+                logging.info("No power monitor serial devices found.  Retrying...")
+            elif not device_list and not wait:
+                logging.error("No power monitor serial devices found.  Exiting")
+                self.Close()
+                sys.exit("No power monitor serial devices found")
+                
+        if device_list:
+            if len(device_list) > 1:
+                logging.error("=======================================")
+                logging.error("More than one power monitor discovered!")
+                logging.error("Test may not execute properly.Aborting test.")
+                logging.error("=======================================")
+                sys.exit("More than one power monitor connected.")
+            device = device_list[0].to_string() # choose the first one
+            if len(device_list) > 1:
+                logging.info("More than one device found.  Using %s"%device)
+            else:
+                logging.info("Power monitor @ %s"%device)
+        else: raise IOError("No device found")
+          
+    self._lockfile = Power_Monitor.lock( device )
+    if log_file_id is not None:
+        self._logfilename = "/tmp/monsoon_%s_%s.%s.log" % (os.uname()[0], os.path.basename(device),
+                                                            log_file_id)
+        self._logfile = open(self._logfilename,'a')
+    else:
+        self._logfile = None
+    try:
+        self.ser = serial.Serial(device, timeout= TIMEOUT_SERIAL)
+    except Exception as e:
+      self.log( "error opening device %s: %s" % (dev, e))
+      self._lockfile.close()
+      raise
+    logging.debug("Setting up power monitor...")
+    self._devicename = device
+    #just in case, stop any active data collection on monsoon
+    self._dataCollectionActive = True
+    self.StopDataCollection()
+    logging.debug("Flushing input...")
+    self._FlushInput()  # discard stale input
+    logging.debug("Getting status....")
+    status = self.GetStatus()
+    
+    if not status:
+      self.log( "no response from device %s" % device)
+      self._lockfile.close()
+      raise IOError("Failed to get status from device")
+    self.start_voltage = status["voltage1"]
+    
+  def __del__(self):
+    self.Close()
+
+  def Close(self):
+    if self._logfile:
+      print("=============\n"+\
+            "Power Monitor log file can be found at '%s'"%self._logfilename +
+            "=============\n")
+      self._logfile.close()
+      self._logfile = None
+    if (self.ser):
+      #self.StopDataCollection()
+      self.ser.flush()
+      self.ser.close()
+      self.ser = None
+    if self._lockfile:
+      self._lockfile.close()
+
+  def log(self, msg , debug = False):
+    if self._logfile: self._logfile.write( msg + "\n")
+    if not debug and LOG_TO_SCREEN:
+      logging.error( msg )
+    else:
+      logging.debug(msg)
+
+  def handle_signal( self, signum, frame):
+    if self.ser:
+      self.ser.flush()
+      self.ser.close()
+      self.ser = None
+    self.log("Got signal %d"%signum)
+    sys.exit("\nGot signal %d\n"%signum)
+    
+  @staticmethod
+  def Discover():
+    monsoon_list = []
+    elapsed = 0
+    logging.info("Discovering power monitor(s)...")
+    ser_device_list = glob.glob("/dev/ttyACM*")
+    logging.info("Seeking devices %s"%ser_device_list)
+    for dev in ser_device_list:
+        try:
+            lockfile = Power_Monitor.lock( dev )
+        except:
+            logging.info( "... device %s in use, skipping"%dev)
+            continue
+        tries = 0
+        ser = None
+        while ser is None and tries < 100:
+             try:  # try to open the device
+                ser = serial.Serial( dev, timeout=TIMEOUT_SERIAL)
+             except Exception as e:
+                logging.error(  "error opening device %s: %s" % (dev, e) )
+                tries += 1
+                time.sleep(2);
+                ser = None
+        logging.info("... found device %s"%dev)
+        lockfile.close()#will be re-locked once monsoon instance created
+        logging.debug("unlocked")
+        if not ser:
+            continue
+        if ser is not None:
+            try:
+                monsoon = Power_Monitor(device = dev)
+                status = monsoon.GetStatus()
+                
+                if not status:
+                    monsoon.log("... no response from device %s, skipping")
+                    continue
+                else:
+                    logging.info("... found power monitor @ %s"%dev)
+                    monsoon_list.append( monsoon )
+            except:
+                import traceback
+                traceback.print_exc()
+                logging.error("... %s appears to not be a monsoon device"%dev)
+    logging.debug("Returning list of %s"%monsoon_list)
+    return monsoon_list
+
+  def GetStatus(self):
+    """ Requests and waits for status.  Returns status dictionary. """
+
+    # status packet format
+    self.log("Getting status...", debug = True)
+    STATUS_FORMAT = ">BBBhhhHhhhHBBBxBbHBHHHHBbbHHBBBbbbbbbbbbBH"
+    STATUS_FIELDS = [
+        "packetType", "firmwareVersion", "protocolVersion",
+        "mainFineCurrent", "usbFineCurrent", "auxFineCurrent", "voltage1",
+        "mainCoarseCurrent", "usbCoarseCurrent", "auxCoarseCurrent", "voltage2",
+        "outputVoltageSetting", "temperature", "status", "leds",
+        "mainFineResistor", "serialNumber", "sampleRate",
+        "dacCalLow", "dacCalHigh",
+        "powerUpCurrentLimit", "runTimeCurrentLimit", "powerUpTime",
+        "usbFineResistor", "auxFineResistor",
+        "initialUsbVoltage", "initialAuxVoltage",
+        "hardwareRevision", "temperatureLimit", "usbPassthroughMode",
+        "mainCoarseResistor", "usbCoarseResistor", "auxCoarseResistor",
+        "defMainFineResistor", "defUsbFineResistor", "defAuxFineResistor",
+        "defMainCoarseResistor", "defUsbCoarseResistor", "defAuxCoarseResistor",
+        "eventCode", "eventData", ]
+
+    self._SendStruct("BBB", 0x01, 0x00, 0x00)
+    while True:  # Keep reading, discarding non-status packets
+      bytes = self._ReadPacket()
+      if not bytes: return None
+      if len(bytes) != struct.calcsize(STATUS_FORMAT) or bytes[0] != "\x10":
+        self.log("wanted status, dropped type=0x%02x, len=%d" % (
+                ord(bytes[0]), len(bytes)))
+        continue
+
+      status = dict(zip(STATUS_FIELDS, struct.unpack(STATUS_FORMAT, bytes)))
+      assert status["packetType"] == 0x10
+      for k in status.keys():
+        if k.endswith("VoltageSetting"):
+          status[k] = 2.0 + status[k] * 0.01
+        elif k.endswith("FineCurrent"):
+          pass # needs calibration data
+        elif k.endswith("CoarseCurrent"):
+          pass # needs calibration data
+        elif k.startswith("voltage") or k.endswith("Voltage"):
+          status[k] = status[k] * 0.000125
+        elif k.endswith("Resistor"):
+          status[k] = 0.05 + status[k] * 0.0001
+          if k.startswith("aux") or k.startswith("defAux"): status[k] += 0.05
+        elif k.endswith("CurrentLimit"):
+          status[k] = 8 * (1023 - status[k]) / 1023.0
+      #self.log( "Returning requested status: \n %s"%(status), debug = True)
+      return status
+
+  def RampVoltage(self, start, end):
+    v = start
+    if v < 3.0: v = 3.0       # protocol doesn't support lower than this
+    while (v < end):
+      self.SetVoltage(v)
+      v += .1
+      time.sleep(.1)
+    self.SetVoltage(end)
+
+  def SetVoltage(self, v):
+    """ Set the output voltage, 0 to disable. """
+    self.log("Setting voltage to %s..."%v, debug = True)
+    if v == 0:
+      self._SendStruct("BBB", 0x01, 0x01, 0x00)
+    else:
+      self._SendStruct("BBB", 0x01, 0x01, int((v - 2.0) * 100))
+    self.log("...Set voltage", debug = True)
+
+  def SetMaxCurrent(self, i):
+    """Set the max output current."""
+    assert i >= 0 and i <= 8
+    self.log("Setting max current to %s..."%i, debug = True)
+    val = 1023 - int((i/8)*1023)
+    self._SendStruct("BBB", 0x01, 0x0a, val & 0xff)
+    self._SendStruct("BBB", 0x01, 0x0b, val >> 8)
+    self.log("...Set max current.", debug = True)
+    
+  def SetUsbPassthrough(self, val):
+    """ Set the USB passthrough mode: 0 = off, 1 = on,  2 = auto. """
+    self._SendStruct("BBB", 0x01, 0x10, val)
+
+  def StartDataCollection(self):    
+    """ Tell the device to start collecting and sending measurement data. """
+    self.log("Starting data collection...", debug = True)
+    self._SendStruct("BBB", 0x01, 0x1b, 0x01) # Mystery command
+    self._SendStruct("BBBBBBB", 0x02, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8)
+    self.log("...started", debug = True)
+    self._dataCollectionActive = True
+    
+  def StopDataCollection(self):
+    """ Tell the device to stop collecting measurement data. """
+    self._SendStruct("BB", 0x03, 0x00) # stop
+    if self._dataCollectionActive:
+      while self.CollectData(False) is not None:
+        pass
+    self._dataCollectionActive = False
+    
+  def CollectData(self, verbose = True):
+    """ Return some current samples.  Call StartDataCollection() first. """
+    #self.log("Collecting data ...", debug = True)
+    while True:  # loop until we get data or a timeout
+      bytes = self._ReadPacket(verbose)
+      
+      if not bytes: return None
+      if len(bytes) < 4 + 8 + 1 or bytes[0] < "\x20" or bytes[0] > "\x2F":
+        if verbose: self.log( "wanted data, dropped type=0x%02x, len=%d" % (
+          ord(bytes[0]), len(bytes)), debug=verbose)
+        continue
+
+      seq, type, x, y = struct.unpack("BBBB", bytes[:4])
+      data = [struct.unpack(">hhhh", bytes[x:x+8])
+              for x in range(4, len(bytes) - 8, 8)]
+
+      if self._last_seq and seq & 0xF != (self._last_seq + 1) & 0xF:
+        self.log( "data sequence skipped, lost packet?" )
+      self._last_seq = seq
+
+      if type == 0:
+        if not self._coarse_scale or not self._fine_scale:
+          self.log("waiting for calibration, dropped data packet")
+          continue
+
+        out = []
+        for main, usb, aux, voltage in data:
+          if main & 1:
+            out.append(((main & ~1) - self._coarse_zero) * self._coarse_scale)
+          else:
+            out.append((main - self._fine_zero) * self._fine_scale)
+        #self.log("...Collected %d samples"%(len(out)), debug = True)
+        return out
+
+      elif type == 1:
+        self._fine_zero = data[0][0]
+        self._coarse_zero = data[1][0]
+
+      elif type == 2:
+        self._fine_ref = data[0][0]
+        self._coarse_ref = data[1][0]
+
+      else:
+        self.log( "discarding data packet type=0x%02x" % type)
+        continue
+
+      if self._coarse_ref != self._coarse_zero:
+        self._coarse_scale = 2.88 / (self._coarse_ref - self._coarse_zero)
+      if self._fine_ref != self._fine_zero:
+        self._fine_scale = 0.0332 / (self._fine_ref - self._fine_zero)
+
+
+  def _SendStruct(self, fmt, *args):
+    """ Pack a struct (without length or checksum) and send it. """
+    data = struct.pack(fmt, *args)
+    data_len = len(data) + 1
+    checksum = (data_len + sum(struct.unpack("B" * len(data), data))) % 256
+    out = struct.pack("B", data_len) + data + struct.pack("B", checksum)
+    self.ser.write(out)
+    self.ser.flush()
+
+  def _ReadPacket(self, verbose = True):
+    """ Read a single data record as a string (without length or checksum). """
+    len_char = self.ser.read(1)
+    if not len_char:
+      if verbose: self.log( "timeout reading from serial port" )
+      return None
+
+    data_len = struct.unpack("B", len_char)
+    data_len = ord(len_char)
+    if not data_len: return ""
+
+    result = self.ser.read(data_len)
+    if len(result) != data_len: return None
+    body = result[:-1]
+    checksum = (data_len + sum(struct.unpack("B" * len(body), body))) % 256
+    if result[-1] != struct.pack("B", checksum):
+      self.log( "Invalid checksum from serial port" )
+      return None
+    return result[:-1]
+
+  def _FlushInput(self):
+    """ Flush all read data until no more available. """
+    self.ser.flushInput()
+    flushed = 0
+    self.log("Flushing input...", debug = True)
+    while True:
+      ready_r, ready_w, ready_x = select.select([self.ser], [], [self.ser], 0)
+      if len(ready_x) > 0:
+        self.log( "exception from serial port" )
+        return None
+      elif len(ready_r) > 0:
+        flushed += 1
+        self.ser.read(1)  # This may cause underlying buffering.
+        self.ser.flush()  # Flush the underlying buffer too.
+      else:
+        break
+    if flushed > 0:
+      self.log( "flushed >%d bytes" % flushed, debug = True )
+
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index 7e6587a..ca4680f 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -6,7 +6,16 @@
     private <fields>;
 }
 
+# ensure we keep public sensor test methods, these are needed at runtime
+-keepclassmembers class * extends com.android.cts.verifier.sensors.base.BaseSensorTestActivity {
+    public <methods>;
+}
+-keepclassmembers class * extends android.hardware.cts.SensorTestCase {
+    public <methods>;
+}
+
 -keepclasseswithmembers class * extends com.android.cts.verifier.location.LocationModeTestActivity
 
 -dontwarn android.hardware.Sensor
+-dontwarn android.test.AndroidTestRunner
 -dontwarn java.util.concurrent.ConcurrentLinkedDeque
diff --git a/apps/CtsVerifier/res/drawable-hdpi/nfc_hce_banner.png b/apps/CtsVerifier/res/drawable-hdpi/nfc_hce_banner.png
new file mode 100644
index 0000000..333b797
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-hdpi/nfc_hce_banner.png
Binary files differ
diff --git a/apps/CtsVerifier/res/layout-land/sensor_test.xml b/apps/CtsVerifier/res/layout-land/sensor_test.xml
new file mode 100644
index 0000000..293b4b0
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-land/sensor_test.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        >
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+
+        <ScrollView
+                android:id="@+id/log_scroll_view"
+                android:fillViewport="true"
+                android:layout_height="match_parent"
+                android:layout_width="0dp"
+                android:layout_weight="1">
+
+            <LinearLayout
+                    android:id="@+id/log_layout"
+                    android:orientation="vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"/>
+
+        </ScrollView>
+
+        <android.opengl.GLSurfaceView android:id="@+id/gl_surface_view"
+                android:visibility="gone"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"/>
+
+    </LinearLayout>
+
+    <include layout="@layout/snsr_next_button" />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout-port/sensor_test.xml b/apps/CtsVerifier/res/layout-port/sensor_test.xml
new file mode 100644
index 0000000..eac5357
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-port/sensor_test.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <ScrollView android:id="@+id/log_scroll_view"
+            android:fillViewport="true"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_width="match_parent">
+
+        <LinearLayout android:id="@+id/log_layout"
+                android:orientation="vertical"
+                android:layout_height="match_parent"
+                android:layout_width="match_parent"/>
+
+    </ScrollView>
+
+    <android.opengl.GLSurfaceView android:id="@+id/gl_surface_view"
+            android:visibility="gone"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_width="match_parent"/>
+
+    <include layout="@layout/snsr_next_button"/>
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_advertiser_hardware_scan_filter.xml b/apps/CtsVerifier/res/layout/ble_advertiser_hardware_scan_filter.xml
new file mode 100644
index 0000000..ce3e1e1
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_advertiser_hardware_scan_filter.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="10dip"
+        >
+
+    <LinearLayout android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            >
+        <TextView android:text="@string/ble_advertiser_scannable"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+        />
+        <TextView android:text="@string/ble_advertiser_scannable_instruction"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+        />
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                >
+            <Button android:id="@+id/ble_advertiser_scannable_start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/ble_advertiser_start"
+                    />
+            <Button android:id="@+id/ble_advertiser_scannable_stop"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/ble_advertiser_stop"
+                    />
+        </LinearLayout>
+        <TextView android:text="@string/ble_advertiser_unscannable"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+        />
+        <TextView android:text="@string/ble_advertiser_unscannable_instruction"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+        />
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                >
+            <Button android:id="@+id/ble_advertiser_unscannable_start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/ble_advertiser_start"
+                    />
+            <Button android:id="@+id/ble_advertiser_unscannable_stop"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/ble_advertiser_stop"
+                    />
+        </LinearLayout>
+    </LinearLayout>
+
+    <include android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            layout="@layout/pass_fail_buttons"
+            />
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_advertiser_power_level.xml b/apps/CtsVerifier/res/layout/ble_advertiser_power_level.xml
new file mode 100644
index 0000000..ec3284d
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_advertiser_power_level.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="10dip"
+        >
+
+    <TextView android:text="@string/ble_advertiser_power_level_instruction"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+    />
+    <LinearLayout android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            >
+        <Button android:id="@+id/ble_power_level_start"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/ble_advertiser_start"
+                />
+        <Button android:id="@+id/ble_power_level_stop"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/ble_advertiser_stop"
+                />
+    </LinearLayout>
+
+    <include android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            layout="@layout/pass_fail_buttons"
+            />
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_advertiser_test.xml b/apps/CtsVerifier/res/layout/ble_advertiser_test.xml
new file mode 100644
index 0000000..7db2b4e
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_advertiser_test.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="10dip"
+        >
+    <ListView android:id="@+id/ble_advertiser_tests"
+            android:layout_height="fill_parent"
+            android:layout_width="match_parent"
+            android:padding="10dip"
+            />
+
+    <include android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            layout="@layout/pass_fail_buttons"
+            />
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_scanner_hardware_scan_filter.xml b/apps/CtsVerifier/res/layout/ble_scanner_hardware_scan_filter.xml
new file mode 100644
index 0000000..f356ded
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_scanner_hardware_scan_filter.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="10dip"
+        >
+    <TextView android:text="@string/ble_scanner_scan_filter_instruction"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+    />
+    <LinearLayout android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            >
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                >
+            <Button android:id="@+id/ble_scan_with_filter"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/ble_scan_with_filter"
+                    />
+            <Button android:id="@+id/ble_scan_without_filter"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/ble_scan_without_filter"
+                    />
+        </LinearLayout>
+        <ListView android:id="@+id/ble_scan_result_list"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent">
+        </ListView>
+    </LinearLayout>
+    <include android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            layout="@layout/pass_fail_buttons"
+    />
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml b/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
new file mode 100644
index 0000000..b240db6
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="10dip"
+        >
+    <TextView android:text="@string/ble_scanner_power_level_instruction"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/ble_scanner_power_level_instruction"
+    />
+    <LinearLayout android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/ble_scanner_power_level_instruction"
+            android:layout_centerInParent="true"
+            android:padding="10dp"
+            >
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerInParent="true"
+                >
+            <TextView android:text="@string/ble_ultra_low"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_ultra_low_mac"
+                  android:layout_width="200dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_ultra_low_rssi"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+            <TextView android:layout_width="100dp"
+                  android:layout_height="wrap_content"/>
+            <TextView android:id="@+id/ble_ultra_low_count"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_ultra_low_set_power"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerInParent="true"
+                >
+            <TextView android:text="@string/ble_low"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_low_mac"
+                  android:layout_width="200dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_low_rssi"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+            <TextView android:layout_width="100dp"
+                  android:layout_height="wrap_content"/>
+            <TextView android:id="@+id/ble_low_count"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_low_set_power"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerInParent="true"
+                >
+            <TextView android:text="@string/ble_medium"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_medium_mac"
+                  android:layout_width="200dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_medium_rssi"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+            <TextView android:layout_width="100dp"
+                  android:layout_height="wrap_content"/>
+            <TextView android:id="@+id/ble_medium_count"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_medium_set_power"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerInParent="true"
+                >
+            <TextView android:text="@string/ble_high"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_high_mac"
+                  android:layout_width="200dp"
+                  android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_high_rssi"
+                  android:layout_width="100dp"
+                  android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <LinearLayout android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+            <TextView android:layout_width="100dp"
+                  android:layout_height="wrap_content"/>
+            <TextView android:id="@+id/ble_high_count"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+            <TextView android:id="@+id/ble_high_set_power"
+                    android:layout_width="100dp"
+                    android:layout_height="wrap_content"
+            />
+        </LinearLayout>
+        <TextView android:id="@+id/ble_timer"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" />
+    </LinearLayout>
+
+    <include android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            layout="@layout/pass_fail_buttons"
+            />
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_scanner_test.xml b/apps/CtsVerifier/res/layout/ble_scanner_test.xml
new file mode 100644
index 0000000..c685d57
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_scanner_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="10dip"
+        >
+    <include android:id="@+id/pass_fail_buttons"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            layout="@layout/pass_fail_buttons"
+            />
+    <ListView android:id="@+id/ble_scanner_tests"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:layout_above="@id/pass_fail_buttons"
+            android:layout_alignParentTop="true"
+            android:padding="10dip"
+            />
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/intent_driven_test.xml b/apps/CtsVerifier/res/layout/intent_driven_test.xml
index e23f4410e..00c1cf6 100644
--- a/apps/CtsVerifier/res/layout/intent_driven_test.xml
+++ b/apps/CtsVerifier/res/layout/intent_driven_test.xml
@@ -1,32 +1,30 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical"
-    >
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
   <ScrollView
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1">
     <TextView android:id="@+id/info"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:textSize="18sp"
-              android:padding="5dp"
-              android:text="@string/dc_start_alarm_test_info"
-        />
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textSize="18sp"
+        android:padding="5dp"
+        android:text="@string/dc_start_alarm_test_info"/>
   </ScrollView>
 
   <LinearLayout android:id="@+id/buttons"
-                android:orientation="horizontal"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
+      android:orientation="horizontal"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"/>
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
-        <include layout="@layout/pass_fail_buttons"/>
-    </LinearLayout>
+      <include layout="@layout/pass_fail_buttons"/>
+  </LinearLayout>
 </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/js_charging.xml b/apps/CtsVerifier/res/layout/js_charging.xml
new file mode 100644
index 0000000..4c0e552
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_charging.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_test_description"
+        android:layout_margin="@dimen/js_padding"/>
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/js_padding"
+        android:text="@string/js_charging_description_1"
+        android:textStyle="bold"/>
+    <Button
+        android:id="@+id/js_charging_start_test_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/js_start_test_text"
+        android:onClick="startTest"
+        android:enabled="false"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/charging_off_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_charging_off_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/js_padding"
+        android:text="@string/js_charging_description_2"
+        android:textStyle="bold"/>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/charging_on_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_charging_on_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_connectivity.xml b/apps/CtsVerifier/res/layout/js_connectivity.xml
new file mode 100644
index 0000000..5208c18
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_connectivity.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_test_description"
+        android:layout_margin="@dimen/js_padding"/>
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_connectivity_description_1"
+        android:layout_margin="@dimen/js_padding"
+        android:textStyle="bold"/>
+
+    <Button
+        android:id="@+id/js_connectivity_start_test_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/js_start_test_text"
+        android:onClick="startTest"
+        android:enabled="false"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/connectivity_off_test_unmetered_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_unmetered_connectivity_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/connectivity_off_test_any_connectivity_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_any_connectivity_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/connectivity_off_test_no_connectivity_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_no_connectivity_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+
+    <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_idle.xml b/apps/CtsVerifier/res/layout/js_idle.xml
new file mode 100644
index 0000000..90e55ec
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_idle.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_test_description"
+        android:layout_margin="@dimen/js_padding"/>
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_idle_description_1"
+        android:layout_margin="@dimen/js_padding"
+        android:textStyle="bold"/>
+
+    <Button
+        android:id="@+id/js_idle_start_test_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/js_start_test_text"
+        android:onClick="startTest"
+        android:enabled="false"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/idle_off_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_idle_item_idle_off"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/idle_on_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_idle_item_idle_on"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/list_content.xml b/apps/CtsVerifier/res/layout/list_content.xml
new file mode 100644
index 0000000..8670283
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/list_content.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 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
+  -->
+<android.support.wearable.view.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ListView
+        android:id="@android:id/list"
+        app:layout_box="all"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</android.support.wearable.view.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/layout/nls_item.xml b/apps/CtsVerifier/res/layout/nls_item.xml
index 3ced3cc..f1a10bf 100644
--- a/apps/CtsVerifier/res/layout/nls_item.xml
+++ b/apps/CtsVerifier/res/layout/nls_item.xml
@@ -40,7 +40,7 @@
         android:text="@string/nls_enable_service" />
 
     <Button
-        android:id="@+id/nls_launch_settings"
+        android:id="@+id/nls_action_button"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentRight="true"
@@ -48,7 +48,7 @@
         android:layout_marginLeft="20dip"
         android:layout_marginRight="20dip"
         android:layout_toRightOf="@id/nls_status"
-        android:onClick="launchSettings"
+        android:onClick="actionPressed"
         android:text="@string/nls_start_settings" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/pa_main.xml b/apps/CtsVerifier/res/layout/pa_main.xml
new file mode 100644
index 0000000..76cb7d4
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pa_main.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <include
+        android:id="@+id/pass_fail_buttons"
+        android:layout_gravity="top"
+        layout="@layout/pass_fail_buttons" />
+
+    <TextureView
+        android:id="@+id/texture_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@id/pass_fail_buttons" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/pass_fail_buttons.xml b/apps/CtsVerifier/res/layout/pass_fail_buttons.xml
index d70e839..5eec539 100644
--- a/apps/CtsVerifier/res/layout/pass_fail_buttons.xml
+++ b/apps/CtsVerifier/res/layout/pass_fail_buttons.xml
@@ -18,26 +18,23 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
 
-    <Button android:id="@+id/pass_button"
+    <ImageButton android:id="@+id/pass_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"            
-            android:drawableTop="@drawable/fs_good"
-            android:text="@string/pass_button_text"/>
+            android:src="@drawable/fs_good"/>
             
-    <Button android:id="@+id/info_button"
+    <ImageButton android:id="@+id/info_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:drawableTop="@drawable/fs_indeterminate"
-            android:visibility="gone"
-            android:text="@string/info_button_text"/>
+            android:src="@drawable/fs_indeterminate"
+            android:visibility="gone"/>
 
-    <Button android:id="@+id/fail_button"
+    <ImageButton android:id="@+id/fail_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"            
-            android:drawableTop="@drawable/fs_error"
-            android:text="@string/fail_button_text"/>
+            android:src="@drawable/fs_error"/>
             
 </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/pca_cubes.xml b/apps/CtsVerifier/res/layout/pca_cubes.xml
new file mode 100644
index 0000000..25869b9
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pca_cubes.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true" >
+
+    <android.opengl.GLSurfaceView
+        android:id="@+id/cube_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/pla_list.xml b/apps/CtsVerifier/res/layout/pla_list.xml
new file mode 100644
index 0000000..0973136
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pla_list.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <ListView
+        android:id="@+id/pla_list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" >
+    </ListView>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/poa_main.xml b/apps/CtsVerifier/res/layout/poa_main.xml
new file mode 100644
index 0000000..578a6a6
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/poa_main.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <include layout="@layout/pass_fail_buttons" />
+
+    <TextView
+        android:id="@+id/poa_status_text"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:textAppearance="@style/InstructionsFont" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/poa_touch.xml b/apps/CtsVerifier/res/layout/poa_touch.xml
new file mode 100644
index 0000000..0085227
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/poa_touch.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+    <com.android.cts.verifier.projection.offscreen.ColorChangeOnKeyView
+        android:id="@+id/multi_touch_view"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/provisioning_byod.xml b/apps/CtsVerifier/res/layout/provisioning_byod.xml
new file mode 100644
index 0000000..989266f
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/provisioning_byod.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        >
+
+    <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1">
+        <TextView
+                android:id="@+id/byod_instructions"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="10dip"
+                android:text="@string/provisioning_byod_instructions"
+                android:textSize="18dip" />
+    </ScrollView>
+
+    <Button
+        android:id="@+id/byod_start"
+        android:layout_width="204dp"
+        android:layout_height="wrap_content"
+        android:text="@string/provisioning_byod_start" />
+
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/provisioning_cross_profile.xml b/apps/CtsVerifier/res/layout/provisioning_cross_profile.xml
new file mode 100644
index 0000000..345e99d
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/provisioning_cross_profile.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical" >
+    <TextView android:id="@+id/text"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <Button
+        android:id="@+id/button_finish"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/provisioning_button_finish" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/pta_touch.xml b/apps/CtsVerifier/res/layout/pta_touch.xml
new file mode 100644
index 0000000..8cf6e89
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pta_touch.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+    <com.android.cts.verifier.projection.touch.TouchPointView
+        android:id="@+id/multi_touch_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/pva_video.xml b/apps/CtsVerifier/res/layout/pva_video.xml
new file mode 100644
index 0000000..a62c833
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pva_video.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <VideoView
+        android:id="@+id/video_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/pwa_buttons.xml b/apps/CtsVerifier/res/layout/pwa_buttons.xml
new file mode 100644
index 0000000..fc2d10f
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pwa_buttons.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="bottom"
+    android:orientation="vertical" >
+
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/pwa_button" />
+
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/pwa_button" />
+
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/pwa_button" />
+
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/pwa_button" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/pwa_widgets.xml b/apps/CtsVerifier/res/layout/pwa_widgets.xml
new file mode 100644
index 0000000..4bfcec6
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pwa_widgets.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+     <TextureView
+         android:id="@+id/texture_view"
+         android:layout_width="match_parent"
+         android:layout_height="match_parent" />
+
+     <LinearLayout
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:orientation="vertical" >
+
+         <LinearLayout
+             android:layout_width="match_parent"
+             android:layout_height="match_parent" >
+
+             <include layout="@layout/pass_fail_buttons" />
+         </LinearLayout>
+
+         <LinearLayout
+             android:layout_width="match_parent"
+             android:layout_height="wrap_content"
+             android:orientation="horizontal" >
+
+             <Button
+                 android:id="@+id/up_button"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:layout_weight="1"
+                 android:text="@string/pwa_button_up" />
+
+             <Button
+                 android:id="@+id/down_button"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:layout_weight="1"
+                 android:text="@string/pwa_button_down" />
+
+             <Button
+                 android:id="@+id/left_button"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent"
+                 android:layout_weight="1"
+                 android:text="@string/pwa_button_left" />
+
+             <Button
+                 android:id="@+id/right_button"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:layout_weight="1"
+                 android:text="@string/pwa_button_right" />
+
+         </LinearLayout>
+     </LinearLayout>
+
+</FrameLayout>
diff --git a/apps/CtsVerifier/res/layout/snsr_error.xml b/apps/CtsVerifier/res/layout/snsr_error.xml
new file mode 100644
index 0000000..d78a8fb
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_error.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/snsr_boxed_padding_bottom"
+        android:paddingTop="@dimen/snsr_boxed_padding_top"
+        android:paddingLeft="@dimen/snsr_boxed_padding_left"
+        android:paddingRight="@dimen/snsr_boxed_padding_right"
+        android:background="@color/snsr_error_background"
+        android:textColor="@color/snsr_error" />
diff --git a/apps/CtsVerifier/res/layout/snsr_information.xml b/apps/CtsVerifier/res/layout/snsr_information.xml
new file mode 100644
index 0000000..e3d9542
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_information.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/snsr_boxed_padding_bottom"
+        android:paddingTop="@dimen/snsr_boxed_padding_top"
+        android:paddingLeft="@dimen/snsr_boxed_padding_left"
+        android:paddingRight="@dimen/snsr_boxed_padding_right"
+        android:background="@color/snsr_information_background"
+        android:textColor="@color/snsr_information" />
diff --git a/apps/CtsVerifier/res/layout/snsr_instruction.xml b/apps/CtsVerifier/res/layout/snsr_instruction.xml
new file mode 100644
index 0000000..e7369c7
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_instruction.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:textColor="?android:attr/textColorSecondary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/snsr_log_padding_bottom"
+        android:paddingTop="@dimen/snsr_log_padding_top"
+        android:paddingLeft="@dimen/snsr_log_padding_left"
+        android:paddingRight="@dimen/snsr_log_padding_right" />
diff --git a/apps/CtsVerifier/res/layout/snsr_message.xml b/apps/CtsVerifier/res/layout/snsr_message.xml
new file mode 100644
index 0000000..cef35ca
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_message.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:textStyle="italic"
+        android:textColor="?android:attr/textColorTertiary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/snsr_log_padding_top"
+        android:paddingLeft="@dimen/snsr_boxed_padding_left"
+        android:paddingRight="@dimen/snsr_boxed_padding_right"
+        android:paddingBottom="@dimen/snsr_log_padding_bottom" />
diff --git a/apps/CtsVerifier/res/layout/snsr_next_button.xml b/apps/CtsVerifier/res/layout/snsr_next_button.xml
new file mode 100644
index 0000000..e7a6d72
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_next_button.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="horizontal"
+        android:gravity="center"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/snsr_view_padding_bottom"
+        android:paddingTop="@dimen/snsr_view_padding_top"
+        >
+
+    <Button android:id="@+id/next_button"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/next_button_text"
+            />
+
+    <Button android:id="@+id/pass_button"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawableTop="@drawable/fs_good"
+            />
+
+    <Button android:id="@+id/fail_button"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawableTop="@drawable/fs_error"
+            />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/snsr_semi_auto_test.xml b/apps/CtsVerifier/res/layout/snsr_semi_auto_test.xml
deleted file mode 100644
index 92039f0..0000000
--- a/apps/CtsVerifier/res/layout/snsr_semi_auto_test.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-    <TextView android:id="@+id/log_text"
-              android:gravity="bottom"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"
-              android:maxLines="27"
-              android:paddingBottom="5dip"
-              android:paddingLeft="10dip"
-              android:paddingRight="10dip"
-              android:paddingTop="5dip"
-              android:scrollbars="vertical"
-            />
-
-    <Button android:id="@+id/next_button"
-            android:layout_alignParentBottom="true"
-            android:layout_centerInParent="true"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="20dip"
-            android:layout_width="120dip"
-            android:text="@string/next_button_text"
-            android:textSize="24dip"
-            />
-
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/snsr_success.xml b/apps/CtsVerifier/res/layout/snsr_success.xml
new file mode 100644
index 0000000..9d600dc
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_success.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/snsr_boxed_padding_bottom"
+        android:paddingTop="@dimen/snsr_boxed_padding_top"
+        android:paddingLeft="@dimen/snsr_boxed_padding_left"
+        android:paddingRight="@dimen/snsr_boxed_padding_right"
+        android:background="@color/snsr_success_background"
+        android:textColor="@color/snsr_success" />
diff --git a/apps/CtsVerifier/res/layout/snsr_test_title.xml b/apps/CtsVerifier/res/layout/snsr_test_title.xml
new file mode 100644
index 0000000..374fb54
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_test_title.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:textStyle="bold"
+        android:textColor="?android:attr/textColorPrimary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/snsr_boxed_padding_bottom"
+        android:paddingTop="@dimen/snsr_boxed_padding_top"
+        android:paddingLeft="@dimen/snsr_boxed_padding_left"
+        android:paddingRight="@dimen/snsr_boxed_padding_right" />
diff --git a/apps/CtsVerifier/res/layout/snsr_warning.xml b/apps/CtsVerifier/res/layout/snsr_warning.xml
new file mode 100644
index 0000000..5d63fc1
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/snsr_warning.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/snsr_boxed_padding_bottom"
+        android:paddingTop="@dimen/snsr_boxed_padding_top"
+        android:paddingLeft="@dimen/snsr_boxed_padding_left"
+        android:paddingRight="@dimen/snsr_boxed_padding_right"
+        android:background="@color/snsr_warning_background"
+        android:textColor="@color/snsr_warning" />
diff --git a/apps/CtsVerifier/res/raw/test_video.mp4 b/apps/CtsVerifier/res/raw/test_video.mp4
new file mode 100644
index 0000000..ab95ac0
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/test_video.mp4
Binary files differ
diff --git a/apps/CtsVerifier/res/values-television/strings.xml b/apps/CtsVerifier/res/values-television/strings.xml
new file mode 100644
index 0000000..1042fa8
--- /dev/null
+++ b/apps/CtsVerifier/res/values-television/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- Don't test these features on televisions. -->
+    <string-array name="disabled_tests">
+        <item>com.android.cts.verifier.notifications.NotificationAttentionManagementVerifierActivity</item>
+        <item>com.android.cts.verifier.notifications.NotificationListenerVerifierActivity</item>
+    </string-array>
+</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values-watch/strings.xml b/apps/CtsVerifier/res/values-watch/strings.xml
new file mode 100644
index 0000000..1f25b04
--- /dev/null
+++ b/apps/CtsVerifier/res/values-watch/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- Don't test these features on watches. -->
+    <string-array name="disabled_tests">
+        <item>com.android.cts.verifier.notifications.NotificationAttentionManagementVerifierActivity</item>
+        <item>com.android.cts.verifier.notifications.NotificationListenerVerifierActivity</item>
+    </string-array>
+</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/attrs.xml b/apps/CtsVerifier/res/values/attrs.xml
new file mode 100644
index 0000000..71a1ba6
--- /dev/null
+++ b/apps/CtsVerifier/res/values/attrs.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <declare-styleable name="BoxInsetLayout_Layout">
+        <attr name="layout_box">
+            <flag name="left" value="0x01" />
+            <flag name="top" value="0x02" />
+            <flag name="right" value="0x04" />
+            <flag name="bottom" value="0x08" />
+            <flag name="all" value="0x0F" />
+        </attr>
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/colors.xml b/apps/CtsVerifier/res/values/colors.xml
new file mode 100644
index 0000000..c855d5f
--- /dev/null
+++ b/apps/CtsVerifier/res/values/colors.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="red">#F00</color>
+    <color name="green">#0F0</color>
+
+    <!-- Sensor tests log colors -->
+    <color name="snsr_error_background">#F5D1D1</color>
+    <color name="snsr_error">#AA0404</color>
+    <color name="snsr_success_background">#DDF6D2</color>
+    <color name="snsr_success">#467701</color>
+    <color name="snsr_warning_background">#F0E4B6</color>
+    <color name="snsr_warning">#75540C</color>
+    <color name="snsr_information_background">#D0D2F6</color>
+    <color name="snsr_information">#41576B</color>
+</resources>
diff --git a/apps/CtsVerifier/res/values/dimens.xml b/apps/CtsVerifier/res/values/dimens.xml
index 00257a9..8df5b35 100644
--- a/apps/CtsVerifier/res/values/dimens.xml
+++ b/apps/CtsVerifier/res/values/dimens.xml
@@ -18,4 +18,24 @@
     <dimen name="widget_margin_bottom">8dp</dimen>
     <dimen name="widget_margin_left">8dp</dimen>
     <dimen name="widget_margin_right">8dp</dimen>
+
+    <!-- Sensor logging values -->
+
+    <dimen name="snsr_boxed_padding_top">15dp</dimen>
+    <dimen name="snsr_boxed_padding_bottom">15dp</dimen>
+    <dimen name="snsr_boxed_padding_left">15dp</dimen>
+    <dimen name="snsr_boxed_padding_right">15dp</dimen>
+
+    <dimen name="snsr_log_padding_top">1dp</dimen>
+    <dimen name="snsr_log_padding_bottom">1dp</dimen>
+    <dimen name="snsr_log_padding_left">8dp</dimen>
+    <dimen name="snsr_log_padding_right">8dp</dimen>
+
+    <dimen name="snsr_view_padding_top">8dp</dimen>
+    <dimen name="snsr_view_padding_bottom">8dp</dimen>
+    <dimen name="snsr_view_padding_left">8dp</dimen>
+    <dimen name="snsr_view_padding_right">8dp</dimen>
+
+    <dimen name="js_padding">10dp</dimen>
+
 </resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index d93649e..3225bcf 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -35,6 +35,7 @@
     <string name="test_category_streaming">Streaming</string>
     <string name="test_category_features">Features</string>
     <string name="test_category_deskclock">Clock</string>
+    <string name="test_category_jobscheduler">Job Scheduler</string>
     <string name="test_category_other">Other</string>
     <string name="clear">Clear</string>
     <string name="test_results_cleared">Test results cleared.</string>
@@ -66,7 +67,10 @@
         \n\nFollow the instructions below to check that the data backup and restore works:
         \n\n1. Make sure backup and automatic restore are enabled in settings. Depending on the
         backup transport supported by the device you may need to do additional steps. For instance
-        you may need to set a Google account as the backup account for the device.
+        you may need to set a Google account as the backup account for the device. If you cannot
+        find the corresponding setting options on your device, run \"adb shell bmgr enable true\"
+        to enable the backup manager. You can check its status by executing \"adb shell bmgr
+        enabled\".
         \n\n2. Run the backup manager: adb shell bmgr run
         \n\n3. Uninstall the program: adb uninstall com.android.cts.verifier
         \n\n4. Reinstall the CTS Verifier and verify that the values are still the same.
@@ -227,6 +231,42 @@
     <string name="ble_server_reliable_write">Waiting on reliable write from client</string>
     <string name="ble_server_receiving_disconnect">Waiting on disconnection from BLE client</string>
 
+    <!-- BLE advertiser side strings -->
+    <string name="ble_advertiser_test_name">BLE Advertiser Test</string>
+    <string name="ble_advertiser_test_info">The BLE test must be done simultaneously on two devices, an advertiser and a scanner. This device is the advertiser.</string>
+    <string name="ble_advertiser_service_name">Bluetooth LE Advertiser Handler Service</string>
+    <string name="ble_privacy_mac_name">BLE Privacy Mac</string>
+    <string name="ble_privacy_mac_info">BLE Advertiser should advertise in non-repeating MAC address.</string>
+    <string name="ble_advertiser_privacy_mac_instruction">Click start to start advertising, you can disconnect USB and lock the screen of advertiser. Counts and mac address will show on scanner. You may receive message that this device does not support BLE advertising.</string>
+    <string name="ble_power_level_name">BLE Tx Power Level</string>
+    <string name="ble_power_level_info">BLE Advertiser advertises in 4 different power levels. Scanner should receive them in different strength of Rssi, cannot receive weak signals beyond several feet.</string>
+    <string name="ble_advertiser_power_level_instruction">Click start to start multi-advertising. Data packets are advertised in 4 different power levels. You may receive message that this device does not support multi advertising. If advertiser does not advertise in 4 power levels, neither you receive the error message, you may not stop the advertising in previous test, or this device does not support 4 advertisers at the same time. Try rebooting the device and run the test to free those advertisers in use.</string>
+    <string name="ble_advertiser_scan_filter_name">BLE Hardware Scan Filter</string>
+    <string name="ble_advertiser_scan_filter_info">BLE Advertiser advertises with 2 different data separately. One can wake up the scanner, the other cannot. This test cares about behavior on scanner only.</string>
+    <string name="ble_advertiser_scannable">Scannable advertising</string>
+    <string name="ble_advertiser_scannable_instruction">Start scannable advertising, expect scanner consume more power on Monsoon monitor, or see log of GattService from scanner logcat.</string>
+    <string name="ble_advertiser_unscannable">Unscannble advertising</string>
+    <string name="ble_advertiser_unscannable_instruction">Start unscannable advertising, expect scanner stay calm on Monsoon monitor, no log of GattService from scanner logcat.</string>
+    <string name="ble_advertiser_start">Start</string>
+    <string name="ble_advertiser_stop">Stop</string>
+
+    <!-- BLE scanner side strings -->
+    <string name="ble_scanner_test_name">BLE Scanner Test</string>
+    <string name="ble_scanner_service_name">Bluetooth LE Scanner Handler Service</string>
+    <string name="ble_scanner_test_info">The BLE test must be done simultaneously on two devices, an advertiser and a scanner. This device is the scanner.</string>
+    <string name="ble_scanner_privacy_mac">Hold for 15 min to see if receive a different MAC address from advertiser.</string>
+    <string name="ble_scanner_privacy_mac_instruction">Mac address, counts are shown on screen. It should continuously receive data packet from advertiser. Every 15 min, a new mac address should show up, which prevents mac address disclosure.</string>
+    <string name="ble_ultra_low">Ultra low</string>
+    <string name="ble_low">Low</string>
+    <string name="ble_medium">Medium</string>
+    <string name="ble_high">High</string>
+    <string name="ble_scanner_power_level_instruction">Count: Ultra low &lt; low &lt; medium &lt; high\nRssi: Ultra low &lt; low &lt; medium &lt; high\nDistance to see count freezing: Ultra low &lt; low &lt; medium &lt; high\nA common error is ultra low, low and medium behave similarly, with similar rssi, freeze at similar distance.\n\n All power level receive a different mac address. After 15 mins, a green text "Get a new Mac address" will show up.</string>
+    <string name="ble_scanner_scan_filter_name">BLE Hardware Scan Filter</string>
+    <string name="ble_scanner_scan_filter_info">Lock the screen of scanner, and connect to monsoon. It will not wake up when advertiser is advertising unscannable, and scanner is scanning with filter.</string>
+    <string name="ble_scanner_scan_filter_instruction">Scan filter is to scan data with service UUID = 0x6666 only. If you scan without scan filter, data with service UUID = 0x5555 and 0x6666 will show up on screen.\nFor monsoon test:\n\tClick scan with filter, lock the screen, connect to monsoon. It will not wake up when advertiser is advertising unscannable data packets, but will show a peak in power usage when advertiser is advertising scannable data.\nFor logcat test:\n\tClick scan with filter, logcat the scanner. No data will be received by GattService when advertiser is advertising unscannable data.</string>
+    <string name="ble_scan_with_filter">Scan with filter</string>
+    <string name="ble_scan_without_filter">Scan without filter</string>
+
     <!-- Strings for FeatureSummaryActivity -->
     <string name="feature_summary">Hardware/Software Feature Summary</string>
     <string name="feature_summary_info">This is a test for...</string>
@@ -367,6 +407,14 @@
     <string name="nfc_hce_conflicting_non_payment_emulator">Two conflicting non-payment services (Emulator)</string>
     <string name="nfc_hce_conflicting_non_payment_reader">Two conflicting non-payment services (Reader)</string>
 
+    <string name="nfc_hce_foreground_non_payment_emulator">Foreground override non-payment services (Emulator)</string>
+    <string name="nfc_hce_foreground_non_payment_reader">Foreground override non-payment services (Reader)</string>
+    <string name="nfc_hce_foreground_non_payment_help">This test enables two non-payment services with conflicting AIDs. It then uses Androids API to allow the foreground app to set a preference for a specific service. This should prevent a popup dialog from showing. If you see a popup dialog during this asking you to select an app, this test has failed.</string>
+
+    <string name="nfc_hce_foreground_payment_emulator">Foreground override payment services (Emulator)</string>
+    <string name="nfc_hce_foreground_payment_reader">Foreground override payment services (Reader)</string>
+    <string name="nfc_hce_foreground_payment_help">This test enables two payment services, and asks you to set one as the default service. It then uses Androids API to allow the foreground app to set a preference for the non-default service. This will cause the non-default payment service to be invoked.</string>
+    <string name="nfc_hce_change_favor_foreground">This test requires the "Favor foreground app" setting to be enabled. Tap OK to go to Tap and Pay settings and check the Favor foreground app option</string>
     <string name="nfc_hce_offhost_service_emulator">Off-host service (Emulator)</string>
     <string name="nfc_hce_offhost_service_reader">Off-host service (Reader)</string>
     <string name="nfc_hce_offhost_emulator_help">This tests enables a service that declares some AIDs to reside off-host. This test only needs to be passed if your device has a secure element (either embedded or UICC.). The responses from the secure element are not verified by the test - it is up to the tester to verify the responses are as expected.</string>
@@ -381,12 +429,33 @@
     <string name="nfc_hce_throughput_emulator">HCE throughput test (Emulator)</string>
     <string name="nfc_hce_throughput_reader">HCE throughput test (Reader)</string>
     <string name="nfc_hce_throughput_emulator_help">This tests verifies that your HCE implementation can reach a decent throughput. While Android does not have any requirements on HCE performance, many HCE applications such as transport and payment apps do. If the average APDU roundtrip time is more than 50ms, please take a look at your implementation to see where the delay is coming from.</string>
-    <string name="nfc_hce_change_preinstalled_wallet">The device has an installed payment application that is currently set as default. To complete the test, you will be asked whether you want to make Payment Service #1 or #2 the default app. Select yes.</string>
+    <string name="nfc_hce_change_preinstalled_wallet">The device has an installed payment application that is currently set as default. To complete the test, you will be asked whether you want to make another app the default app. Select yes.</string>
     <string name="nfc_hce_change_default_help">You will now be asked whether you want to make Payment Service #1 the default app. Select yes.</string>
     <string name="nfc_hce_conflicting_non_payment_help">When tapping the first time, you will be shown a dialog that asks you to choose between TransportService #1 and TransportService #2. Select TransportService #2. Verify a dialog is shown that asks you to tap again to complete. Now tap again, and if communication with TransportService #2 is successfull the pass button will be enabled."</string>
+
+    <string name="nfc_hce_payment_dynamic_aids_emulator">Dynamic payment AIDs (Emulator)</string>
+    <string name="nfc_hce_payment_dynamic_aids_reader">Dynamic payment AIDs (Reader)</string>
+    <string name="nfc_hce_payment_dynamic_aids_help">This test tries to register dynamic AIDs for a payment service.</string>
+
+    <string name="nfc_hce_payment_prefix_aids_emulator">Payment prefix AIDs (Emulator)</string>
+    <string name="nfc_hce_payment_prefix_aids_reader">Payment prefix AIDs (Reader)</string>
+    <string name="nfc_hce_payment_prefix_aids_help">This test statically registers prefix AIDs for a payment service.</string>
+
+    <string name="nfc_hce_payment_prefix_aids_emulator_2">Payment prefix AIDs 2 (Emulator)</string>
+    <string name="nfc_hce_payment_prefix_aids_reader_2">Payment prefix AIDs 2 (Reader)</string>
+
+    <string name="nfc_hce_other_prefix_aids_emulator">Other prefix AIDs (Emulator)</string>
+    <string name="nfc_hce_other_prefix_aids_reader">Other prefix AIDs (Reader)</string>
+    <string name="nfc_hce_other_prefix_aids_help">This test dynamically registers prefix AIDs for a non-payment service.</string>
+
+    <string name="nfc_hce_other_conflicting_prefix_aids_emulator">Conflicting non-payment prefix AIDs (Emulator)</string>
+    <string name="nfc_hce_other_conflicting_prefix_aids_reader">Conflicting non-payment prefix AIDs (Reader)</string>
+    <string name="nfc_hce_other_conflicting_prefix_aids_help">This test registers conflicting prefix AIDs and makes sure AID conflict detection with prefix AIDs works properly. When tapping the first time, you will be shown a dialog that asks you to choose between TransportService #1 and TransportService #2. Select TransportService #2. Verify a dialog is shown that asks you to tap again to complete. Now tap again, and if communication with TransportService #2 is successfull the pass button will be enabled."</string>
+
     <string name="nfc_payment_service_desc">NFC Payment service</string>
     <string name="ppse">PPSE</string>
     <string name="mastercard">MasterCard</string>
+    <string name="visa">Visa</string>
     <string name="paymentService1">Payment Service #1</string>
     <string name="paymentService2">Payment Service #2</string>
     <string name="transportService1">TransportService #1</string>
@@ -395,10 +464,58 @@
     <string name="offhostService">OffhostService</string>
 
     <!-- Strings for Sensor Test Activities -->
+    <string name="snsr_device_admin_receiver">Sensor Tests Device Admin Receiver</string>
+    <string name="snsr_test_summary">Tests passed: %1$d, Tests skipped: %2$d, Tests failed: %3$d</string>
+    <string name="snsr_test_complete">Test completed without errors.</string>
+    <string name="snsr_test_complete_with_errors">Test completed with errors: those errors
+        might degrade the user experience and might cause some applications to misbehave. They are
+        not required for Android Compatibility at this time, but will in a future release.</string>
+    <string name="snsr_test_pass">PASS</string>
+    <string name="snsr_test_skipped">SKIPPED</string>
+    <string name="snsr_test_fail">FAIL</string>
+    <string name="snsr_execution_time">Test execution time %1$s sec</string>
+
+    <!-- Strings to interact with users in Sensor Tests -->
+    <string name="snsr_test_play_sound">A sound will be played once the verification is complete...</string>
+    <string name="snsr_no_interaction">Leave the device on top of a flat surface.</string>
+    <string name="snsr_interaction_needed">Once the test begins, you will have to wave your hand over the front of the device.</string>
+    <string name="snsr_device_steady">Keep the device steady.</string>
+    <string name="snsr_keep_device_rotating_clockwise">Once the test begins, you will have to keep rotating the device clockwise.</string>
+    <string name="snsr_wait_for_user">Press \'Next\' to continue.</string>
+    <string name="snsr_wait_to_begin">Press \'Next\' to begin.</string>
+    <string name="snsr_on_complete_return">After completing the task, go back to this test.</string>
+    <string name="snsr_movement_expected">Movement was expected during the test. Found=%1$b.</string>
+    <string name="snsr_sensor_feature_deactivation">Turn off any special features installed in the
+        device that register for sensors. Once you are done, you can begin the test.</string>
+    <string name="snsr_setting_mode_request">You will be redirected to set \'%1$s\' to: %2$s.</string>
+    <string name="snsr_setting_mode_set">\'%1$s\' set to: %2$s.</string>
+    <string name="snsr_setting_mode_not_set">\'%1$s\' not set to: %2$s.</string>
+    <string name="snsr_setting_airplane_mode">Airplane mode</string>
+    <string name="snsr_setting_screen_brightness_mode">Adaptive Brightness</string>
+    <string name="snsr_setting_auto_rotate_screen_mode">Auto-rotate screen</string>
+    <string name="snsr_setting_keep_screen_on">Stay awake</string>
+    <string name="snsr_setting_location_mode">Location</string>
+    <string name="snsr_setting_ambient_display">Ambient Display</string>
+    <string name="snsr_pass_on_error">Pass Anyway</string>
+    <string name="snsr_run_automated_tests">The screen will be turned off to execute the tests,
+        when tests complete, the device will vibrate and the screen will be turned back on.</string>
+
     <!-- Accelerometer -->
     <string name="snsr_accel_test">Accelerometer Test</string>
     <string name="snsr_accel_test_info">This test verifies that the accelerometer is working properly. As you move the device around through space, the triangle should always point down (i.e. in the direction of gravity.) If it does not, the accelerometer is improperly configured.</string>
     <string name="snsr_accel_m_test">Accelerometer Measurement Tests</string>
+    <string name="snsr_accel_test_face_up">Place the device on a flat surface with the screen
+        facing the ceiling.</string>
+    <string name="snsr_accel_test_face_down">Place the device on a flat surface with the screen
+        facing it.</string>
+    <string name="snsr_accel_test_right_side">Place the device in a flat surface resting vertically
+        on its right side.</string>
+    <string name="snsr_accel_test_left_side">Place the device in a flat surface resting vertically
+        on its left side.</string>
+    <string name="snsr_accel_test_top_side">Place the device in a flat surface resting vertically
+        on its top side.</string>
+    <string name="snsr_accel_test_bottom_side">Place the device in a flat surface resting vertically
+        on its bottom side.</string>
 
     <!-- Gyroscope -->
     <string name="snsr_gyro_test">Gyroscope Test</string>
@@ -409,6 +526,13 @@
     <string name="snsr_gyro_test_degrees_title">Wrong units?</string>
     <string name="snsr_gyro_test_degrees_message">These values looks like degrees per second. These should be radians per second!</string>
     <string name="snsr_gyro_m_test">Gyroscope Measurement Test</string>
+    <string name="snsr_gyro_device_placement">Place the device in a flat surface with the screen
+        facing the ceiling. Read the instructions for each scenario, before you perform the
+        test.</string>
+    <string name="snsr_gyro_device_static">Leave the device static.</string>
+    <string name="snsr_gyro_rotate_device">Once you begin the test, you will need to rotate the
+        device 360deg (one time) in the direction show by the animation, then place it back on the
+        flat surface.</string>
 
     <!-- Heart Rate -->
     <string name="snsr_heartrate_test">Heart Rate Test</string>
@@ -418,6 +542,62 @@
 
     <!-- Magnetic Field -->
     <string name="snsr_mag_m_test">Magnetic Field Measurement Tests</string>
+    <string name="snsr_mag_verify_norm">Verifying the Norm...</string>
+    <string name="snsr_mag_verify_std_dev">Verifying the Standard Deviation...</string>
+    <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>
+    <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">-&gt; (%1$.2f, %2$.2f, %3$.2f) : %4$.2f uT</string>
+
+    <!-- Sensor Value Accuracy -->
+    <string name="snsr_rot_vec_test">Rotation Vector Accuracy Test</string>
+    <string name="snsr_event_length">Sensor(%3$s). Event values expected to have size=%1$d. Found=%2$d.</string>
+    <string name="snsr_event_value">Sensor(%3$s). Event value[0] expected to be of value=%1$f. Found=%2$f.</string>
+    <string name="snsr_event_time">Sensor(%5$s). Event timestamp expected to be synchronized with SystemClock.elapsedRealtimeNanos(). Event received at=%1$d. Event timestamp=%2$d. Delta=%3$d. Threshold=%4$d.</string>
+
+    <!-- Sensor Batching -->
+    <string name="snsr_batch_test">Sensor Batching Tests</string>
+    <string name="snsr_batching_walking_needed">Once the test begins, you will have to take the
+        device in your hand and walk.</string>
+
+    <!-- Sensor Synchronization -->
+    <string name="snsr_synch_test">Sensor Synchronization Test</string>
+
+    <!-- Step Counter and Detector -->
+    <string name="snsr_step_counter_test">Step Counter and Detector Tests</string>
+    <string name="snsr_step_counter_test_walking">Once the test begins, you will need to walk, and tap on the screen with each step you take.</string>
+    <string name="snsr_step_counter_test_still">Once the test begins, you will need to remain still and hold the device still in your hand.</string>
+    <string name="snsr_step_counter_expected_steps">At least %1$d steps are expected to be reported. Reported=%2$d.</string>
+    <string name="snsr_step_counter_detected_reported">Steps reported by user=%1$d. Steps counted=%2$d. Delta=%3$d. Tolerance=%4$d.</string>
+    <string name="snsr_step_detector_detected_reported">Steps reported by user=%1$d. Steps detected=%2$d. Delta=%3$d. Tolerance=%4$d.</string>
+    <string name="snsr_step_counter_event_changed">Step counter expected to increase monotonically, with a delta > 0. Found=%1$d. Timestamp=%2$d.</string>
+    <string name="snsr_step_reported">%1$d | User reported step.</string>
+    <string name="snsr_step_counter_event">%1$d | Step Counter event. count=%2$d.</string>
+    <string name="snsr_step_detector_event">%1$d | Step Detector event.</string>
+
+    <!-- Significant Motion -->
+    <string name="snsr_significant_motion_test">Significant Motion Tests</string>
+    <string name="snsr_significant_motion_event_arrival">Event expected to trigger. Triggered=%1$s.</string>
+    <string name="snsr_significant_motion_event_type">Event expected to be of type=%1$d. Found=%2$d.</string>
+    <string name="snsr_significant_motion_event_unexpected">Event not expected to trigger. Triggered=%1$s.</string>
+    <string name="snsr_significant_motion_disable_info">Significant Motion is expected to disable itself after it triggers once.</string>
+    <string name="snsr_significant_motion_test_trigger">Once you begin the test, you will need to walk for Significant Motion to be detected.</string>
+    <string name="snsr_significant_motion_test_cancel">Once you begin the test, you will need to walk to ensure Significant Motion is not reported after trigger canceled.</string>
+    <string name="snsr_significant_motion_test_vibration">Leave the device in a level surface. Once you begin the test, the device will vibrate to ensure that Significant Motion is not triggered.</string>
+    <string name="snsr_significant_motion_test_in_hand">Once you begin the test, hold the device in your hand while you perform natural hand movements.</string>
+    <string name="snsr_significant_motion_test_sitting">Once you begin the test, keep the device in your pocket and move naturally while sitting in a chair.</string>
+    <string name="snsr_significant_motion_test_deactivation">Once you begin the test, you will need to walk to ensure Significant Motion triggers only once.</string>
+    <string name="snsr_significant_motion_registration">Expected to be able to register for TriggerSensor. Found=%1$b.</string>
+    <string name="snsr_significant_motion_cancelation">Expected to be able to cancel TriggerSensor. Found=%b.</string>
+
+    <!-- Strings for Sensor CTS tests inside CtsVerifier -->
+    <string name="snsr_single_sensor_tests">CTS Single Sensor Tests</string>
+    <string name="snsr_sensor_integration_tests">CTS Sensor Integration Tests</string>
+    <string name="snsr_sensor_test">CTS Sensor Test</string>
+    <string name="snsr_sensor_batching_tests">CTS Sensor Batching Tests</string>
 
     <!-- Strings for Sample Test Activities -->
     <string name="share_button_text">Share</string>
@@ -567,6 +747,7 @@
 
     <!-- Strings for USB accessory test activity -->
     <string name="usb_accessory_test">USB Accessory Test</string>
+    <string name="sensor_power_test">Sensor Power Test</string>
     <string name="usb_accessory_test_info">
         1. Connect your Android device to a computer and run the \'cts-usb-accessory\' program
         included with the CTS Verifier bundle.
@@ -760,10 +941,35 @@
         itself according to the current rotation of the device.</string>
 
     <string name="test_category_notifications">Notifications</string>
+    <string name="attention_test">Notification Attention Management Test</string>
+    <string name="attention_info">This test checks that the NotificationManagerService is
+        respecting user preferences about notification ranking and filtering.
+    </string>
+    <string name="attention_ready">I\'m done</string>
+    <string name="attention_filter_all">Please set the notification filter to \"All\" in the dialog
+        that appears when you change the device\'s volume.</string>
+    <string name="attention_filter_priority">Please set the notification filter to \"Priority\" in
+        the dialog that appears when you change the device\'s volume, and allow messages from
+        starred contacts.</string>
+    <string name="attention_filter_none">Please set the notification filter to \"None\" in the dialog
+        that appears when you change the device\'s volume.</string>
+    <string name="attention_create_contacts">Create contacts for notification annotations.</string>
+    <string name="attention_delete_contacts">Delete test contacts.</string>
+    <string name="attention_default_order">Check that ranker defaults to time order.</string>
+    <string name="attention_priority_order">Check that ranker respects developers priorities.</string>
+    <string name="attention_ambient_bit">Check that the ambient bit is set appropriately.</string>
+    <string name="attention_lookup_order">Check that ranker respects Lookup URIs for contacts.</string>
+    <string name="attention_email_order">Check that ranker respects mailto URIs for contacts.</string>
+    <string name="attention_phone_order">Check that ranker respects telephone URIs for contacts.</string>
+    <string name="attention_interruption_order">Check that ranker temporarily boosts interruptions.
+    This test takes 15 seconds to complete.</string>
+    <string name="attention_none_are_filtered">Check that \"All\" mode doesn\'t filter any notifications.</string>
+    <string name="attention_some_are_filtered">Check that \"Priority\" mode doesn\'t filter priority notifications.</string>
+    <string name="attention_all_are_filtered">Check that \"None\" mode filters all notifications.</string>
     <string name="nls_test">Notification Listener Test</string>
     <string name="nls_service_name">Notification Listener for CTS Verifier</string>
     <string name="nls_info">This test checks that a NotificationListenerService can be enabled
-        and disabled, and that once enabled the service is able to receive notificaitons and
+        and disabled, and that once enabled the service is able to receive notifications and
         dismiss them.
     </string>
     <string name="nls_enable_service">Please enable \"Notification Listener for CTS Verifier\"
@@ -932,7 +1138,6 @@
         2. Verify that a timer is started  and the timers UI is shown with a timer named "Start Timer Test".\n
         3. Verify that the timer rings after 30 seconds.\n
     </string>
-    
     <!-- Strings for LockConfirmBypassTest -->
     <string name="lock_confirm_test_title">Keyguard Password Verification</string>
     <string name="lock_set_button_text">Set password</string>
@@ -943,4 +1148,153 @@
         \nThen click the \"Change password\" button to change it. You should be prompted for the current password first. If you are not, then mark the test as failed.
     </string>
 
+    <!-- String for Projection Tests -->
+    <string name="test_category_projection">Projection Tests</string>
+    <string name="projection_service_name">Projection Service</string>
+    <string name="pca_info">This tests whether or not OpenGL projection works.\n
+        You should see two "tumbling cubes." Tapping the screen should case the cubes to explode.</string>
+    <string name="pca_test">Projection Cube Test</string>
+    <string name="pwa_info">This tests whether or displaying widets and keyfocus navigation works.\n
+        You should see four buttons on the bottom of the screen.\n
+        Pressing the "up" and "down" buttons should highlight different buttons.\n
+        Further, you should also be able to touch them and they should highlight as usual.</string>
+    <string name="pwa_test">Projection Widget Test</string>
+    <string name="pwa_button_up">Up</string>
+    <string name="pwa_button_down">Down</string>
+    <string name="pwa_button_left">Left</string>
+    <string name="pwa_button_right">Right</string>
+    <string name="pwa_button">Button</string>
+    <string name="pla_test">Projection Scrolling List Test</string>
+    <string name="pla_info">This tests whether a projected list view will scroll properly\n
+        You should see 50 list items and be able to scroll up and down the list</string>
+    <string name="pva_test">Projection Video Playback Test</string>
+    <string name="pva_info">This tests whether video playback works when projected.\n
+        You should see a blinking white box and here a beep that is synchronized with each blink</string>
+    <string name="pta_test">Projection Multitouch Test</string>
+    <string name="pta_info">This tests whether multitouch works.\n
+        Touching the screen should render a dot at the location you touched.\n
+        Touching with additional fingers will render additoinal dots and you should be able to drag them around.</string>
+    <string name="poa_test">Projection Offscreen Activity</string>
+    <string name="poa_info">This tests whether a virtual display will continue to respond to and render even when the screen is off.\n
+        Simply follow the instructions and the test will detect the pass conditions.\n
+        Note that turning on the screen too early will result in a failure.</string>
+
+    <!-- Strings for RotationVectorTest and GameRotationVectorTest -->
+    <string name="rotation_vector_test">Rotation Vector Accuracy Test</string>
+    <string name="snsr_rotation_vector_set_reference">
+        Place the mobile device in a reference position. Note: to provide an accurate reference,
+        align the device along one edge of a notebook laying on a table.</string>
+    <string name="snsr_rotation_vector_reference_set">Reference position set.</string>
+    <string name="snsr_rotation_vector_move_info">Move, shake, and rotate the device.</string>
+    <string name="snsr_rotation_vector_set_final">Place the device back to the reference position.</string>
+    <string name="snsr_rotation_vector_verification">Angular deviation [%1$4.1f %2$4.1f %3$4.1f]. Current: %4$f deg. Max tolerated: %5$f.</string>
+
+    <!-- Strings for BYOD managed provisioning tests (ByodFlowTestActivity) -->
+    <string name="test_category_managed_provisioning">Managed Provisioning</string>
+    <string name="provisioning_byod_device_admin">CTS Verifier - BYOD Admin</string>
+    <string name="provisioning_byod">BYOD Managed Provisioning</string>
+    <string name="provisioning_byod_info">
+        This test exercises the BYOD managed provisioning flow.
+        Start by pressing the button on screen and follow instructions to finish the managed provisioning process.
+        If your device has not been encrypted before, it will be encrypted and rebooted.
+        After the provisioning process completes, return to this page and carry out further verifications.
+    </string>
+    <string name="provisioning_byod_start">Start BYOD provisioning flow</string>
+    <string name="provisioning_byod_instructions">
+        1. Press the button below to start the managed provisioning flow.
+        If your device has not been encrypted before, it will reboot to apply encryption.
+        After reboot follow instructions in the notification area to complete the provisioning.\n
+        2. After successful provisioning, you should be automatically redirected back to this page.
+        Please press through the following verification steps.
+        Allow a few seconds after returning from provisioning, as the profile owner test should automatically pass.
+    </string>
+    <string name="provisioning_byod_profileowner">Profile owner installed</string>
+    <string name="provisioning_byod_diskencryption">Full disk encryption enabled</string>
+    <string name="provisioning_byod_profile_visible">Work profile visible in Settings</string>
+    <string name="provisioning_byod_admin_visible">Device administrator visible in Settings</string>
+    <string name="provisioning_byod_workapps_visible">Badged work apps visible in Launcher</string>
+    <string name="provisioning_byod_cross_profile">Open app cross profiles</string>
+    <string name="provisioning_byod_cross_profile_app_personal">
+        You selected the CTS Verifier option.
+    </string>
+    <string name="provisioning_byod_cross_profile_app_work">You selected the Work option.</string>
+    <string name="provisioning_byod_cross_profile_instruction">
+        Please press the Go button to start an action.\n
+        \n
+        You should be asked to choose either \"CTS Verifier\" or \"Work\" to complete the action.
+        Pressing either should bring up a page stating your choice.\n
+        \n
+        Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+    </string>
+    <string name="provisioning_byod_profile_visible_instruction">
+        Please press the Go button to open the Settings page.
+        Navigate to Accounts and confirm that:\n
+        \n
+        - Both Personal and Work categories exist.\n
+        - \"Remove work profile\" exists under the Work category.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="provisioning_byod_admin_visible_instruction">
+        Please press the Go button to open the Security page in Settings.
+        Navigate to Device administrators and confirm that:\n
+        \n
+        - Both Personal and Work categories exist.\n
+        - \"CTS Verifier - BYOD Admin\" exists under the Work category, and is activated.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="provisioning_byod_workapps_visible_instruction">
+        Please press the Go button to start the launcher.
+        Go to All Apps screen and scroll through it to confirm that:\n
+        \n
+        - A new set of work apps including CTS Verifier appear in the list.\n
+        - Work badge overlay appears on work app\'s icon.\n
+        \n
+        Then navigate back to this screen using Recents button.
+    </string>
+    <string name="provisioning_byod_no_activity">Cannot communicate with activity in the work profile.</string>
+    <string name="provisioning_byod_delete_profile">Initiate deletion of work profile.</string>
+    <string name="provisioning_byod_profile_deleted">Work profile deleted.</string>
+    <string name="provisioning_byod_disabled">Device provisioning is not enabled.</string>
+    <string name="provisioning_byod_go">Go</string>
+    <string name="provisioning_button_finish">Finish</string>
+    <string name="provisioning_cross_profile_chooser">Choose an app to complete action</string>
+
+    <!-- Strings for DeviceOwnerProvisioningTest -->
+    <string name="provisioning_device_owner">Device Owner Provisioning</string>
+    <string name="device_owner_provisioning_tests">Device Owner provisioning tests</string>
+    <string name="device_owner_provisioning_tests_info">The device owner provisioning tests verify that setting up a corporate owned device can only be done on a factory reset device.</string>
+    <string name="device_owner_provisioning_category">Device Owner Provisioning</string>
+    <string name="device_owner_negative_test">Device owner negative test</string>
+    <string name="device_owner_negative_test_info">Please click the "Start provisioning" button, and when you see a warning dialog telling the device is already set up, select "pass". Otherwise, select "fail".</string>
+    <string name="start_device_owner_provisioning_button">Start provisioning</string>
+
+    <!-- Strings for JobScheduler Tests -->
+    <string name="js_test_description">This test is mostly automated, but requires some user interaction. You can pass this test once the list items below are checked.</string>
+
+    <string name="js_idle_test">Idle Mode Constraints</string>
+    <string name="js_start_test_text">Start test</string>
+    <string name="js_idle_instructions">Verify the behaviour of the JobScheduler API for when the device is in idle mode. Simply follow the on-screen instructions.</string>
+    <string name="js_idle_description_1">Turn the screen off and then back on in order to begin.</string>
+    <string name="js_idle_item_idle_off">Idle job does not execute when device is not idle.</string>
+    <string name="js_idle_item_idle_on">Idle job does execute when device is forced into idle.</string>
+
+    <string name="js_charging_test">Charging Constraints</string>
+    <string name="js_charging_instructions">Verify the behaviour of the JobScheduler API for when the device is on power and unplugged from power. Simply follow the on-screen instructions.</string>
+    <string name="js_charging_description_1">Unplug the phone in order to begin.</string>
+    <string name="js_charging_off_test">Device not charging will not execute a job with a charging constraint.</string>
+    <string name="js_charging_on_test">Device when charging will execute a job with a charging constraint.</string>
+    <string name="js_charging_description_2">After the above test has passed, plug the device back in to continue. If the above failed, you can simply fail this test.</string>
+
+    <string name="js_connectivity_test">Connectivity Constraints</string>
+    <string name="js_connectivity_instructions">Verify the behaviour of the JobScheduler API for when the device has no access to data connectivity. Simply follow the on-screen instructions.</string>
+    <string name="js_connectivity_description_1">Disable WiFi and Cellular data to begin.</string>
+    <string name="js_unmetered_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
+    <string name="js_any_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
+    <string name="js_no_connectivity_test">Device with no connectivity will still execute a job with no connectivity constraints.</string>
+
+    <!-- A list of fully-qualified test classes that should not be run. -->
+    <string-array name="disabled_tests" />
+
 </resources>
diff --git a/apps/CtsVerifier/res/xml/access_prefix_aid_list.xml b/apps/CtsVerifier/res/xml/access_prefix_aid_list.xml
new file mode 100644
index 0000000..915c041
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/access_prefix_aid_list.xml
@@ -0,0 +1,3 @@
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/accessService">
+</host-apdu-service>
diff --git a/apps/CtsVerifier/res/xml/device_admin_byod.xml b/apps/CtsVerifier/res/xml/device_admin_byod.xml
new file mode 100644
index 0000000..0408ce2
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/device_admin_byod.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<!-- BEGIN_INCLUDE(meta_data) -->
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+    <uses-policies>
+        <encrypted-storage />
+        <wipe-data />
+    </uses-policies>
+</device-admin>
+<!-- END_INCLUDE(meta_data) -->
diff --git a/apps/CtsVerifier/res/xml/empty_aid_list.xml b/apps/CtsVerifier/res/xml/empty_aid_list.xml
new file mode 100644
index 0000000..0646fd9
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/empty_aid_list.xml
@@ -0,0 +1,3 @@
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/transportService1">
+</host-apdu-service>
diff --git a/apps/CtsVerifier/res/xml/payment_aid_list_1.xml b/apps/CtsVerifier/res/xml/payment_aid_list_1.xml
index 2036402..37344ff 100644
--- a/apps/CtsVerifier/res/xml/payment_aid_list_1.xml
+++ b/apps/CtsVerifier/res/xml/payment_aid_list_1.xml
@@ -1,5 +1,6 @@
 <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
-    android:description="@string/paymentService1">
+    android:description="@string/paymentService1"
+    android:apduServiceBanner="@drawable/nfc_hce_banner">
         <aid-group android:description="@string/paymentService1" android:category="payment">
             <aid-filter android:name="325041592E5359532E4444463031"
                         android:description="@string/ppse"/>
diff --git a/apps/CtsVerifier/res/xml/payment_aid_list_2.xml b/apps/CtsVerifier/res/xml/payment_aid_list_2.xml
index 36a5af0..fbf9ce5 100644
--- a/apps/CtsVerifier/res/xml/payment_aid_list_2.xml
+++ b/apps/CtsVerifier/res/xml/payment_aid_list_2.xml
@@ -1,5 +1,5 @@
 <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
-    android:description="@string/paymentService2">
+    android:description="@string/paymentService2" android:apduServiceBanner="@drawable/nfc_hce_banner">
         <aid-group android:description="@string/paymentService2" android:category="payment">
             <aid-filter android:name="325041592E5359532E4444463031"
                         android:description="@string/ppse"/>
diff --git a/apps/CtsVerifier/res/xml/payment_empty_aid_list.xml b/apps/CtsVerifier/res/xml/payment_empty_aid_list.xml
new file mode 100644
index 0000000..6daf5ea
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/payment_empty_aid_list.xml
@@ -0,0 +1,9 @@
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/paymentService1" android:apduServiceBanner="@drawable/nfc_hce_banner">
+        <aid-group android:description="@string/paymentService1" android:category="payment">
+            <aid-filter android:name="325041592E5359532E4444463031"
+                        android:description="@string/ppse"/>
+            <aid-filter android:name="A0000000041010"
+                        android:description="@string/mastercard"/>
+        </aid-group>
+</host-apdu-service>
diff --git a/apps/CtsVerifier/res/xml/payment_prefix_aid_list.xml b/apps/CtsVerifier/res/xml/payment_prefix_aid_list.xml
new file mode 100644
index 0000000..cea5600
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/payment_prefix_aid_list.xml
@@ -0,0 +1,11 @@
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/paymentService1" android:apduServiceBanner="@drawable/nfc_hce_banner">
+        <aid-group android:description="@string/paymentService1" android:category="payment">
+            <aid-filter android:name="325041592E5359532E4444463031"
+                        android:description="@string/ppse"/>
+            <aid-prefix-filter android:name="A000000004"
+                        android:description="@string/mastercard"/>
+            <aid-prefix-filter android:name="A000000003"
+                        android:description="@string/visa"/>
+        </aid-group>
+</host-apdu-service>
diff --git a/apps/CtsVerifier/res/xml/payment_prefix_aid_list_2.xml b/apps/CtsVerifier/res/xml/payment_prefix_aid_list_2.xml
new file mode 100644
index 0000000..67b4d90
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/payment_prefix_aid_list_2.xml
@@ -0,0 +1,19 @@
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/paymentService1" android:apduServiceBanner="@drawable/nfc_hce_banner">
+        <aid-group android:description="@string/paymentService1" android:category="payment">
+            <aid-filter android:name="325041592E5359532E4444463031"
+                        android:description="@string/ppse"/>
+            <aid-prefix-filter android:name="A00000000410"
+                        android:description="@string/mastercard"/>
+            <aid-prefix-filter android:name="A0000000041010"
+                        android:description="@string/mastercard"/>
+            <aid-prefix-filter android:name="A00000000310"
+                        android:description="@string/visa"/>
+        </aid-group>
+        <aid-group android:description="@string/transportService1" android:category="other">
+            <aid-prefix-filter android:name="F0000000FF"
+                        android:description="@string/transportService1"/>
+            <aid-prefix-filter android:name="F000000000"
+                        android:description="@string/transportService1"/>
+        </aid-group>
+</host-apdu-service>
diff --git a/apps/CtsVerifier/res/xml/sensor_device_admin.xml b/apps/CtsVerifier/res/xml/sensor_device_admin.xml
new file mode 100644
index 0000000..2a3437d
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/sensor_device_admin.xml
@@ -0,0 +1,20 @@
+<!-- Copyright (C) 2011 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.
+-->
+
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+    <uses-policies>
+        <force-lock />
+    </uses-policies>
+</device-admin>
diff --git a/apps/CtsVerifier/res/xml/transport_prefix_aid_list_1.xml b/apps/CtsVerifier/res/xml/transport_prefix_aid_list_1.xml
new file mode 100644
index 0000000..0646fd9
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/transport_prefix_aid_list_1.xml
@@ -0,0 +1,3 @@
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/transportService1">
+</host-apdu-service>
diff --git a/apps/CtsVerifier/res/xml/transport_prefix_aid_list_2.xml b/apps/CtsVerifier/res/xml/transport_prefix_aid_list_2.xml
new file mode 100644
index 0000000..44b1772
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/transport_prefix_aid_list_2.xml
@@ -0,0 +1,3 @@
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/transportService2">
+</host-apdu-service>
diff --git a/apps/CtsVerifier/src/android/support/wearable/view/BoxInsetLayout.java b/apps/CtsVerifier/src/android/support/wearable/view/BoxInsetLayout.java
new file mode 100644
index 0000000..95bac11
--- /dev/null
+++ b/apps/CtsVerifier/src/android/support/wearable/view/BoxInsetLayout.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2014 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.support.wearable.view;
+
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+
+/**
+ * BoxInsetLayout is a screen shape-aware FrameLayout that can box its children
+ * in the center square of a round screen by using the
+ * {@code layout_box} attribute. The values for this attribute specify the
+ * child's edges to be boxed in:
+ * {@code left|top|right|bottom} or {@code all}.
+ * The {@code layout_box} attribute is ignored on a device with a rectangular
+ * screen.
+ */
+public class BoxInsetLayout extends FrameLayout {
+
+    private static float FACTOR = 0.146467f; //(1 - sqrt(2)/2)/2
+    private static final int DEFAULT_CHILD_GRAVITY = Gravity.TOP | Gravity.START;
+
+    private Rect mForegroundPadding;
+    private boolean mLastKnownRound;
+    private Rect mInsets;
+
+    public BoxInsetLayout(Context context) {
+        this(context, null);
+    }
+
+    public BoxInsetLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BoxInsetLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        // make sure we have foreground padding object
+        if (mForegroundPadding == null) {
+            mForegroundPadding = new Rect();
+        }
+        if (mInsets == null) {
+            mInsets = new Rect();
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        requestApplyInsets();
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        insets = super.onApplyWindowInsets(insets);
+        final boolean round = insets.isRound();
+        if (round != mLastKnownRound) {
+            mLastKnownRound = round;
+            requestLayout();
+        }
+        mInsets.set(
+                insets.getSystemWindowInsetLeft(),
+                insets.getSystemWindowInsetTop(),
+                insets.getSystemWindowInsetRight(),
+                insets.getSystemWindowInsetBottom());
+        return insets;
+    }
+
+    /**
+     * determine screen shape
+     * @return true if on a round screen
+     */
+    public boolean isRound() {
+        return mLastKnownRound;
+    }
+
+    /**
+     * @return the system window insets Rect
+     */
+    public Rect getInsets() {
+        return mInsets;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int count = getChildCount();
+        // find max size
+        int maxWidth = 0;
+        int maxHeight = 0;
+        int childState = 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                LayoutParams lp = (BoxInsetLayout.LayoutParams) child.getLayoutParams();
+                int marginLeft = 0;
+                int marginRight = 0;
+                int marginTop = 0;
+                int marginBottom = 0;
+                if (mLastKnownRound) {
+                    // round screen, check boxed, don't use margins on boxed
+                    if ((lp.boxedEdges & LayoutParams.BOX_LEFT) == 0) {
+                        marginLeft = lp.leftMargin;
+                    }
+                    if ((lp.boxedEdges & LayoutParams.BOX_RIGHT) == 0) {
+                        marginRight = lp.rightMargin;
+                    }
+                    if ((lp.boxedEdges & LayoutParams.BOX_TOP) == 0) {
+                        marginTop = lp.topMargin;
+                    }
+                    if ((lp.boxedEdges & LayoutParams.BOX_BOTTOM) == 0) {
+                        marginBottom = lp.bottomMargin;
+                    }
+                } else {
+                    // rectangular, ignore boxed, use margins
+                    marginLeft = lp.leftMargin;
+                    marginTop = lp.topMargin;
+                    marginRight = lp.rightMargin;
+                    marginBottom = lp.bottomMargin;
+                }
+                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+                maxWidth = Math.max(maxWidth,
+                        child.getMeasuredWidth() + marginLeft + marginRight);
+                maxHeight = Math.max(maxHeight,
+                        child.getMeasuredHeight() + marginTop + marginBottom);
+                childState = combineMeasuredStates(childState, child.getMeasuredState());
+            }
+        }
+        // Account for padding too
+        maxWidth += getPaddingLeft() + mForegroundPadding.left
+                + getPaddingRight() + mForegroundPadding.right;
+        maxHeight += getPaddingTop() + mForegroundPadding.top
+                + getPaddingBottom() + mForegroundPadding.bottom;
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+        // Check against our foreground's minimum height and width
+        final Drawable drawable = getForeground();
+        if (drawable != null) {
+            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+        }
+
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+
+        // determine boxed inset
+        int boxInset = (int) (FACTOR * Math.max(getMeasuredWidth(), getMeasuredHeight()));
+        // adjust the match parent children
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+
+            final LayoutParams lp = (BoxInsetLayout.LayoutParams) child.getLayoutParams();
+            int childWidthMeasureSpec;
+            int childHeightMeasureSpec;
+            int plwf = getPaddingLeft() + mForegroundPadding.left;
+            int prwf = getPaddingRight() + mForegroundPadding.right;
+            int ptwf = getPaddingTop() + mForegroundPadding.top;
+            int pbwf = getPaddingBottom() + mForegroundPadding.bottom;
+
+            // adjust width
+            int totalPadding = 0;
+            int totalMargin = 0;
+            // BoxInset is a padding. Ignore margin when we want to do BoxInset.
+            if (mLastKnownRound && ((lp.boxedEdges & LayoutParams.BOX_LEFT) != 0)) {
+                totalPadding = boxInset;
+            } else {
+                totalMargin = plwf + lp.leftMargin;
+            }
+            if (mLastKnownRound && ((lp.boxedEdges & LayoutParams.BOX_RIGHT) != 0)) {
+                totalPadding += boxInset;
+            } else {
+                totalMargin += prwf + lp.rightMargin;
+            }
+            if (lp.width == LayoutParams.MATCH_PARENT) {
+                //  Only subtract margin from the actual width, leave the padding in.
+                childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        getMeasuredWidth() - totalMargin, MeasureSpec.EXACTLY);
+            } else {
+                childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                        totalPadding + totalMargin, lp.width);
+            }
+
+            // adjust height
+            if (mLastKnownRound && ((lp.boxedEdges & LayoutParams.BOX_TOP) != 0)) {
+                totalPadding = boxInset;
+            } else {
+                totalMargin = ptwf + lp.topMargin;
+            }
+            if (mLastKnownRound && ((lp.boxedEdges & LayoutParams.BOX_BOTTOM) != 0)) {
+                totalPadding += boxInset;
+            } else {
+                totalMargin += pbwf + lp.bottomMargin;
+            }
+
+            if (lp.height == LayoutParams.MATCH_PARENT) {
+                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        getMeasuredHeight() - totalMargin, MeasureSpec.EXACTLY);
+            } else {
+                childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                        totalPadding + totalMargin, lp.height);
+            }
+
+            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+        }
+    }
+
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        layoutBoxChildren(left, top, right, bottom, false /* no force left gravity */);
+    }
+
+    private void layoutBoxChildren(int left, int top, int right, int bottom,
+            boolean forceLeftGravity) {
+        final int count = getChildCount();
+        int boxInset = (int)(FACTOR * Math.max(right - left, bottom - top));
+
+        final int parentLeft = getPaddingLeft() + mForegroundPadding.left;
+        final int parentRight = right - left - getPaddingRight() - mForegroundPadding.right;
+
+        final int parentTop = getPaddingTop() + mForegroundPadding.top;
+        final int parentBottom = bottom - top - getPaddingBottom() - mForegroundPadding.bottom;
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                final int width = child.getMeasuredWidth();
+                final int height = child.getMeasuredHeight();
+
+                int childLeft;
+                int childTop;
+
+                int gravity = lp.gravity;
+                if (gravity == -1) {
+                    gravity = DEFAULT_CHILD_GRAVITY;
+                }
+
+                final int layoutDirection = getLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
+                final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+
+                // These values are replaced with boxInset below as necessary.
+                int paddingLeft = child.getPaddingLeft();
+                int paddingRight = child.getPaddingRight();
+                int paddingTop = child.getPaddingTop();
+                int paddingBottom = child.getPaddingBottom();
+
+                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.CENTER_HORIZONTAL:
+                        childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
+                                lp.leftMargin - lp.rightMargin;
+                        break;
+                    case Gravity.RIGHT:
+                        if (!forceLeftGravity) {
+                            if (mLastKnownRound
+                                    && ((lp.boxedEdges & LayoutParams.BOX_RIGHT) != 0)) {
+                                paddingRight = boxInset;
+                                childLeft = right - left - width;
+                            } else {
+                                childLeft = parentRight - width - lp.rightMargin;
+                            }
+                            break;
+                        }
+                    case Gravity.LEFT:
+                    default:
+                        if (mLastKnownRound && ((lp.boxedEdges & LayoutParams.BOX_LEFT) != 0)) {
+                            paddingLeft = boxInset;
+                            childLeft = 0;
+                        } else {
+                            childLeft = parentLeft + lp.leftMargin;
+                        }
+                }
+
+                switch (verticalGravity) {
+                    case Gravity.TOP:
+                        if (mLastKnownRound && ((lp.boxedEdges & LayoutParams.BOX_TOP) != 0)) {
+                            paddingTop = boxInset;
+                            childTop = 0;
+                        } else {
+                            childTop = parentTop + lp.topMargin;
+                        }
+                        break;
+                    case Gravity.CENTER_VERTICAL:
+                        childTop = parentTop + (parentBottom - parentTop - height) / 2 +
+                                lp.topMargin - lp.bottomMargin;
+                        break;
+                    case Gravity.BOTTOM:
+                        if (mLastKnownRound && ((lp.boxedEdges & LayoutParams.BOX_BOTTOM) != 0)) {
+                            paddingBottom = boxInset;
+                            childTop = bottom - top - height;
+                        } else {
+                            childTop = parentBottom - height - lp.bottomMargin;
+                        }
+                        break;
+                    default:
+                        childTop = parentTop + lp.topMargin;
+                }
+
+                child.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+                child.layout(childLeft, childTop, childLeft + width, childTop + height);
+            }
+        }
+    }
+
+    public void setForeground(Drawable drawable) {
+        super.setForeground(drawable);
+        if (mForegroundPadding == null) {
+            mForegroundPadding = new Rect();
+        }
+        drawable.getPadding(mForegroundPadding);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return new LayoutParams(p);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new BoxInsetLayout.LayoutParams(getContext(), attrs);
+    }
+
+    /**
+     * adds {@code layout_box} attribute to layout parameters
+     */
+    public static class LayoutParams extends FrameLayout.LayoutParams {
+
+        public static final int BOX_NONE = 0x0;
+        public static final int BOX_LEFT = 0x01;
+        public static final int BOX_TOP = 0x02;
+        public static final int BOX_RIGHT = 0x04;
+        public static final int BOX_BOTTOM = 0x08;
+        public static final int BOX_ALL = 0x0F;
+
+        public int boxedEdges = BOX_NONE;
+
+        public LayoutParams(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            TypedArray a = context.obtainStyledAttributes(attrs,  R.styleable.BoxInsetLayout_Layout, 0, 0);
+            boxedEdges = a.getInt(R.styleable.BoxInsetLayout_Layout_layout_box, BOX_NONE);
+            a.recycle();
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(int width, int height, int gravity) {
+            super(width, height, gravity);
+        }
+
+        public LayoutParams(int width, int height, int gravity, int boxed) {
+            super(width, height, gravity);
+            boxedEdges = boxed;
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(ViewGroup.MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(FrameLayout.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+            this.boxedEdges = source.boxedEdges;
+            this.gravity = source.gravity;
+        }
+
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
index 9b53bfd..6495a05 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
@@ -20,6 +20,7 @@
 
 import android.app.ListActivity;
 import android.content.Intent;
+import android.os.Bundle;
 import android.view.View;
 import android.widget.ListView;
 
@@ -53,6 +54,12 @@
         }
     }
 
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.list_content);
+    }
+
     private void handleLaunchTestResult(int resultCode, Intent data) {
         if (resultCode == RESULT_OK) {
             TestResult testResult = TestResult.fromActivityResult(resultCode, data);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index 1f19cbe..ebddf4f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -22,12 +22,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
+import android.util.Log;
 import android.widget.ListView;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -67,6 +69,21 @@
  *             <meta-data android:name="test_required_features" android:value="android.hardware.sensor.accelerometer" />
  *         </pre>
  *     </li>
+ *     <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present, the
+ *         test gets excluded from being shown. If the device has any of the excluded features then
+ *         the test will not appear in the test list. Use a colon (:) to specify multiple features
+ *         to exclude for the test. Note that the colon means "or" in this case.
+ *         <pre>
+ *             <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
+ *         </pre>
+ *     </li>
+ *     <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present,
+ *         the test is applicable to run. If the device has any of the applicable features then
+ *         the test will appear in the test list. Use a colon (:) to specify multiple features
+ *         <pre>
+ *             <meta-data android:name="test_applicable_features" android:value="android.hardware.sensor.compass" />
+ *         </pre>
+ *     </li>
  *
  * </ol>
  */
@@ -78,6 +95,12 @@
 
     private static final String TEST_REQUIRED_FEATURES_META_DATA = "test_required_features";
 
+    private static final String TEST_EXCLUDED_FEATURES_META_DATA = "test_excluded_features";
+
+    private static final String TEST_APPLICABLE_FEATURES_META_DATA = "test_applicable_features";
+
+    private final HashSet<String> mDisabledTests;
+
     private Context mContext;
 
     private String mTestParent;
@@ -86,6 +109,12 @@
         super(context);
         mContext = context;
         mTestParent = testParent;
+
+        String[] disabledTestArray = context.getResources().getStringArray(R.array.disabled_tests);
+        mDisabledTests = new HashSet<>(disabledTestArray.length);
+        for (int i = 0; i < disabledTestArray.length; i++) {
+            mDisabledTests.add(disabledTestArray[i]);
+        }
     }
 
     @Override
@@ -148,11 +177,18 @@
         int size = list.size();
         for (int i = 0; i < size; i++) {
             ResolveInfo info = list.get(i);
+            if (info.activityInfo == null || mDisabledTests.contains(info.activityInfo.name)) {
+                Log.w("CtsVerifier", "ignoring disabled test: " + info.activityInfo.name);
+                continue;
+            }
             String title = getTitle(mContext, info.activityInfo);
             String testName = info.activityInfo.name;
             Intent intent = getActivityIntent(info.activityInfo);
             String[] requiredFeatures = getRequiredFeatures(info.activityInfo.metaData);
-            TestListItem item = TestListItem.newTest(title, testName, intent, requiredFeatures);
+            String[] excludedFeatures = getExcludedFeatures(info.activityInfo.metaData);
+            String[] applicableFeatures = getApplicableFeatures(info.activityInfo.metaData);
+            TestListItem item = TestListItem.newTest(title, testName, intent, requiredFeatures,
+                    excludedFeatures, applicableFeatures);
 
             String testCategory = getTestCategory(mContext, info.activityInfo.metaData);
             addTestToCategory(testsByCategory, testCategory, item);
@@ -190,6 +226,32 @@
         }
     }
 
+    static String[] getExcludedFeatures(Bundle metaData) {
+        if (metaData == null) {
+            return null;
+        } else {
+            String value = metaData.getString(TEST_EXCLUDED_FEATURES_META_DATA);
+            if (value == null) {
+                return null;
+            } else {
+                return value.split(":");
+            }
+        }
+    }
+
+    static String[] getApplicableFeatures(Bundle metaData) {
+        if (metaData == null) {
+            return null;
+        } else {
+            String value = metaData.getString(TEST_APPLICABLE_FEATURES_META_DATA);
+            if (value == null) {
+                return null;
+            } else {
+                return value.split(":");
+            }
+        }
+    }
+
     static String getTitle(Context context, ActivityInfo activityInfo) {
         if (activityInfo.labelRes != 0) {
             return context.getString(activityInfo.labelRes);
@@ -216,19 +278,36 @@
         tests.add(item);
     }
 
+    private boolean hasAnyFeature(String[] features) {
+        if (features != null) {
+            PackageManager packageManager = mContext.getPackageManager();
+            for (String feature : features) {
+                if (packageManager.hasSystemFeature(feature)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean hasAllFeatures(String[] features) {
+        if (features != null) {
+            PackageManager packageManager = mContext.getPackageManager();
+            for (String feature : features) {
+                if (!packageManager.hasSystemFeature(feature)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
     List<TestListItem> filterTests(List<TestListItem> tests) {
-        List<TestListItem> filteredTests = new ArrayList<TestListItem>(tests);
-        PackageManager packageManager = mContext.getPackageManager();
-        Iterator<TestListItem> iterator = filteredTests.iterator();
-        while (iterator.hasNext()) {
-            TestListItem item = iterator.next();
-            String[] requiredFeatures = item.requiredFeatures;
-            if (requiredFeatures != null) {
-                for (int i = 0; i < requiredFeatures.length; i++) {
-                    if (!packageManager.hasSystemFeature(requiredFeatures[i])) {
-                        iterator.remove();
-                        break;
-                    }
+        List<TestListItem> filteredTests = new ArrayList<TestListItem>();
+        for (TestListItem test : tests) {
+            if (!hasAnyFeature(test.excludedFeatures) && hasAllFeatures(test.requiredFeatures)) {
+                if (test.applicableFeatures == null || hasAnyFeature(test.applicableFeatures)) {
+                    filteredTests.add(test);
                 }
             }
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index ef80b5d..444a250 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -31,7 +31,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.Button;
+import android.widget.ImageButton;
 
 /**
  * {@link Activity}s to handle clicks to the pass and fail buttons of the pass fail buttons layout.
@@ -77,7 +77,7 @@
          */
         void setInfoResources(int titleId, int messageId, int viewId);
 
-        Button getPassButton();
+        View getPassButton();
 
         /**
          * Returns a unique identifier for the test.  Usually, this is just the class name.
@@ -86,6 +86,13 @@
 
         /** @return null or details about the test run. */
         String getTestDetails();
+
+        /**
+         * Set the result of the test and finish the activity.
+         *
+         * @param passed Whether or not the test passed.
+         */
+        void setTestResultAndFinish(boolean passed);
     }
 
     public static class Activity extends android.app.Activity implements PassFailActivity {
@@ -120,7 +127,7 @@
         }
 
         @Override
-        public Button getPassButton() {
+        public View getPassButton() {
             return getPassButtonView(this);
         }
 
@@ -138,6 +145,12 @@
         public String getTestDetails() {
             return null;
         }
+
+        @Override
+        public void setTestResultAndFinish(boolean passed) {
+            PassFailButtons.setTestResultAndFinishHelper(this, getTestId(), getTestDetails(),
+                    passed);
+        }
     }
 
     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
@@ -153,7 +166,7 @@
         }
 
         @Override
-        public Button getPassButton() {
+        public View getPassButton() {
             return getPassButtonView(this);
         }
 
@@ -171,6 +184,12 @@
         public String getTestDetails() {
             return null;
         }
+
+        @Override
+        public void setTestResultAndFinish(boolean passed) {
+            PassFailButtons.setTestResultAndFinishHelper(this, getTestId(), getTestDetails(),
+                    passed);
+        }
     }
 
     public static class TestListActivity extends AbstractTestListActivity
@@ -187,7 +206,7 @@
         }
 
         @Override
-        public Button getPassButton() {
+        public View getPassButton() {
             return getPassButtonView(this);
         }
 
@@ -205,6 +224,12 @@
         public String getTestDetails() {
             return null;
         }
+
+        @Override
+        public void setTestResultAndFinish(boolean passed) {
+            PassFailButtons.setTestResultAndFinishHelper(this, getTestId(), getTestDetails(),
+                    passed);
+        }
     }
 
     private static <T extends android.app.Activity & PassFailActivity>
@@ -328,11 +353,11 @@
             default:
                 throw new IllegalArgumentException("Unknown id: " + target.getId());
         }
-        setTestResultAndFinish(activity, testId, testDetails, passed);
+        setTestResultAndFinishHelper(activity, testId, testDetails, passed);
     }
 
     /** Set the test result and finish the activity. */
-    public static void setTestResultAndFinish(android.app.Activity activity, String testId,
+    private static void setTestResultAndFinishHelper(android.app.Activity activity, String testId,
             String testDetails, boolean passed) {
         if (passed) {
             TestResult.setPassedResult(activity, testId, testDetails);
@@ -343,7 +368,7 @@
         activity.finish();
     }
 
-    private static Button getPassButtonView(android.app.Activity activity) {
-        return (Button) activity.findViewById(R.id.pass_button);
+    private static ImageButton getPassButtonView(android.app.Activity activity) {
+        return (ImageButton) activity.findViewById(R.id.pass_button);
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
index 2cc79fb..afe3a73 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
@@ -83,14 +83,46 @@
         /** Features necessary to run this test. */
         final String[] requiredFeatures;
 
+        /** Features such that, if any present, the test gets excluded from being shown. */
+        final String[] excludedFeatures;
+
+        /** If any of of the features are present the test is meaningful to run. */
+        final String[] applicableFeatures;
+
+        public static TestListItem newTest(Context context, int titleResId, String testName,
+                Intent intent, String[] requiredFeatures, String[] excludedFeatures,
+                String[] applicableFeatures) {
+            return newTest(context.getString(titleResId), testName, intent, requiredFeatures,
+                    excludedFeatures, applicableFeatures);
+        }
+
+        public static TestListItem newTest(Context context, int titleResId, String testName,
+                Intent intent, String[] requiredFeatures, String[] excludedFeatures) {
+            return newTest(context.getString(titleResId), testName, intent, requiredFeatures,
+                    excludedFeatures, null);
+        }
+
         public static TestListItem newTest(Context context, int titleResId, String testName,
                 Intent intent, String[] requiredFeatures) {
-            return newTest(context.getString(titleResId), testName, intent, requiredFeatures);
+            return newTest(context.getString(titleResId), testName, intent, requiredFeatures, null,
+                    null);
+        }
+
+        public static TestListItem newTest(String title, String testName, Intent intent,
+                String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) {
+            return new TestListItem(title, testName, intent, requiredFeatures, excludedFeatures,
+                    applicableFeatures);
+        }
+
+        public static TestListItem newTest(String title, String testName, Intent intent,
+                String[] requiredFeatures, String[] excludedFeatures) {
+            return new TestListItem(title, testName, intent, requiredFeatures, excludedFeatures,
+                    null);
         }
 
         public static TestListItem newTest(String title, String testName, Intent intent,
                 String[] requiredFeatures) {
-            return new TestListItem(title, testName, intent, requiredFeatures);
+            return new TestListItem(title, testName, intent, requiredFeatures, null, null);
         }
 
         public static TestListItem newCategory(Context context, int titleResId) {
@@ -98,15 +130,17 @@
         }
 
         public static TestListItem newCategory(String title) {
-            return new TestListItem(title, null, null, null);
+            return new TestListItem(title, null, null, null, null, null);
         }
 
         private TestListItem(String title, String testName, Intent intent,
-                String[] requiredFeatures) {
+                String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) {
             this.title = title;
             this.testName = testName;
             this.intent = intent;
             this.requiredFeatures = requiredFeatures;
+            this.excludedFeatures = excludedFeatures;
+            this.applicableFeatures = applicableFeatures;
         }
 
         boolean isTest() {
@@ -366,4 +400,4 @@
 
         }
     }
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserHardwareScanFilterActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserHardwareScanFilterActivity.java
new file mode 100644
index 0000000..be2fef9
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserHardwareScanFilterActivity.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+public class BleAdvertiserHardwareScanFilterActivity extends PassFailButtons.Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_advertiser_hardware_scan_filter);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_advertiser_scan_filter_name,
+                         R.string.ble_advertiser_scan_filter_info, -1);
+
+        ((Button) findViewById(R.id.ble_advertiser_scannable_start))
+            .setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    Intent intent = new Intent(BleAdvertiserHardwareScanFilterActivity.this,
+                                               BleAdvertiserService.class);
+                    intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
+                                    BleAdvertiserService.COMMAND_START_SCANNABLE);
+                    startService(intent);
+                }
+            });
+        ((Button)findViewById(R.id.ble_advertiser_scannable_stop))
+            .setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    stopAdvertising();
+                }
+            });
+        ((Button)findViewById(R.id.ble_advertiser_unscannable_start))
+            .setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    Intent intent = new Intent(BleAdvertiserHardwareScanFilterActivity.this,
+                                               BleAdvertiserService.class);
+                    intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
+                                    BleAdvertiserService.COMMAND_START_UNSCANNABLE);
+                    startService(intent);
+                }
+        });
+        ((Button)findViewById(R.id.ble_advertiser_unscannable_stop))
+            .setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    stopAdvertising();
+                }
+        });
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BleAdvertiserService.BLE_ADV_NOT_SUPPORT);
+        filter.addAction(BleAdvertiserService.BLE_START_SCANNABLE);
+        filter.addAction(BleAdvertiserService.BLE_START_UNSCANNABLE);
+        filter.addAction(BleAdvertiserService.BLE_STOP_SCANNABLE);
+        filter.addAction(BleAdvertiserService.BLE_STOP_UNSCANNABLE);
+        registerReceiver(onBroadcast, filter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(onBroadcast);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopAdvertising();
+    }
+
+    private void showMessage(String msg) {
+        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+    }
+
+    private void pass() {
+        this.setTestResultAndFinish(true);
+    }
+
+    private void stopAdvertising() {
+        Intent intent = new Intent(BleAdvertiserHardwareScanFilterActivity.this,
+                                   BleAdvertiserService.class);
+        intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
+                        BleAdvertiserService.COMMAND_STOP_SCANNABLE);
+        intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
+                        BleAdvertiserService.COMMAND_STOP_UNSCANNABLE);
+        startService(intent);
+    }
+
+    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case BleAdvertiserService.BLE_START_SCANNABLE:
+                    showMessage("Start advertising, this should be scanned");
+                    break;
+                case BleAdvertiserService.BLE_START_UNSCANNABLE:
+                    showMessage("Start advertising, this should not be scanned");
+                    break;
+                case BleAdvertiserService.BLE_STOP_SCANNABLE:
+                case BleAdvertiserService.BLE_STOP_UNSCANNABLE:
+                    showMessage("Stop advertising");
+                    break;
+                case BleAdvertiserService.BLE_ADV_NOT_SUPPORT:
+                    pass();
+                    break;
+            }
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPowerLevelActivity.java
new file mode 100644
index 0000000..1cc9206
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPowerLevelActivity.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+public class BleAdvertiserPowerLevelActivity extends PassFailButtons.Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_advertiser_power_level);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_power_level_name,
+                         R.string.ble_power_level_info, -1);
+
+        ((Button) findViewById(R.id.ble_power_level_start))
+            .setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    Intent intent = new Intent(BleAdvertiserPowerLevelActivity.this,
+                                               BleAdvertiserService.class);
+                    intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
+                                    BleAdvertiserService.COMMAND_START_POWER_LEVEL);
+                    startService(intent);
+                }
+            });
+        ((Button) findViewById(R.id.ble_power_level_stop))
+            .setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    stopAdvertising();
+                }
+            });
+
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BleAdvertiserService.BLE_START_POWER_LEVEL);
+        filter.addAction(BleAdvertiserService.BLE_STOP_POWER_LEVEL);
+        filter.addAction(BleAdvertiserService.BLE_ADV_NOT_SUPPORT);
+        registerReceiver(onBroadcast, filter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(onBroadcast);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopAdvertising();
+    }
+
+    private void stopAdvertising() {
+        Intent intent = new Intent(BleAdvertiserPowerLevelActivity.this,
+                                   BleAdvertiserService.class);
+        intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
+                        BleAdvertiserService.COMMAND_STOP_POWER_LEVEL);
+        startService(intent);
+    }
+
+    private void showMessage(String msg) {
+        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+    }
+
+    private void pass() {
+        this.setTestResultAndFinish(true);
+    }
+
+    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case BleAdvertiserService.BLE_START_POWER_LEVEL:
+                    showMessage("Start advertising, please hold for a while.");
+                    break;
+                case BleAdvertiserService.BLE_STOP_POWER_LEVEL:
+                    showMessage("Stop advertising");
+                    break;
+                case BleAdvertiserService.BLE_ADV_NOT_SUPPORT:
+                    pass();
+                    break;
+            }
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
new file mode 100644
index 0000000..281b2e8
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import java.util.UUID;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.util.Log;
+import android.widget.Toast;
+
+public class BleAdvertiserService extends Service {
+
+    public static final boolean DEBUG = true;
+    public static final String TAG = "BleAdvertiseService";
+
+    public static final int COMMAND_START_ADVERTISE = 0;
+    public static final int COMMAND_STOP_ADVERTISE = 1;
+    public static final int COMMAND_START_POWER_LEVEL = 2;
+    public static final int COMMAND_STOP_POWER_LEVEL = 3;
+    public static final int COMMAND_START_SCANNABLE = 4;
+    public static final int COMMAND_STOP_SCANNABLE = 5;
+    public static final int COMMAND_START_UNSCANNABLE = 6;
+    public static final int COMMAND_STOP_UNSCANNABLE = 7;
+
+    public static final String BLE_ADV_NOT_SUPPORT =
+            "com.android.cts.verifier.bluetooth.BLE_ADV_NOT_SUPPORT";
+    public static final String BLE_START_ADVERTISE =
+            "com.android.cts.verifier.bluetooth.BLE_START_ADVERTISE";
+    public static final String BLE_STOP_ADVERTISE =
+            "com.android.cts.verifier.bluetooth.BLE_STOP_ADVERTISE";
+    public static final String BLE_START_POWER_LEVEL =
+            "com.android.cts.verifier.bluetooth.BLE_START_POWER_LEVEL";
+    public static final String BLE_STOP_POWER_LEVEL =
+            "com.android.cts.verifier.bluetooth.BLE_STOP_POWER_LEVEL";
+    public static final String BLE_START_SCANNABLE =
+            "com.android.cts.verifier.bluetooth.BLE_START_SCANNABLE";
+    public static final String BLE_START_UNSCANNABLE =
+            "com.android.cts.verifier.bluetooth.BLE_START_UNSCANNABLE";
+    public static final String BLE_STOP_SCANNABLE =
+            "com.android.cts.verifier.bluetooth.BLE_STOP_SCANNABLE";
+    public static final String BLE_STOP_UNSCANNABLE =
+            "com.android.cts.verifier.bluetooth.BLE_STOP_UNSCANNABLE";
+
+    public static final String EXTRA_COMMAND =
+            "com.android.cts.verifier.bluetooth.EXTRA_COMMAND";
+
+    protected static final UUID PRIVACY_MAC_UUID =
+            UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
+    protected static final UUID POWER_LEVEL_UUID =
+            UUID.fromString("00008888-0000-1000-8000-00805f9b34fb");
+    protected static final UUID SCAN_RESP_UUID =
+            UUID.fromString("00007777-0000-1000-8000-00805f9b34fb");
+    protected static final UUID SCANNABLE_UUID =
+            UUID.fromString("00006666-0000-1000-8000-00805f9b34fb");
+    protected static final UUID UNSCANNABLE_UUID =
+            UUID.fromString("00005555-0000-1000-8000-00805f9b34fb");
+
+    public static final byte MANUFACTURER_TEST_ID = (byte)0x07;
+    public static final byte[] PRIVACY_MAC_DATA = new byte[]{3, 1, 4};
+    public static final byte[] PRIVACY_RESPONSE = new byte[]{9, 2, 6};
+    public static final byte[] POWER_LEVEL_DATA = new byte[]{1, 5, 0};
+    public static final byte[] POWER_LEVEL_MASK = new byte[]{1, 1, 0};
+    public static final byte[] SCANNABLE_DATA = new byte[]{5, 3, 5};
+    public static final byte[] UNSCANNABLE_DATA = new byte[]{8, 9, 7};
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothAdapter mBluetoothAdapter;
+    private BluetoothLeAdvertiser mAdvertiser;
+    private BluetoothGattServer mGattServer;
+    private AdvertiseCallback mCallback;
+    private Handler mHandler;
+
+    private int[] mPowerLevel;
+    private Map<Integer, AdvertiseCallback> mPowerCallback;
+    private int mAdvertiserStatus;
+
+    private AdvertiseCallback mScannableCallback;
+    private AdvertiseCallback mUnscannableCallback;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mBluetoothAdapter = mBluetoothManager.getAdapter();
+        mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
+        mGattServer = mBluetoothManager.openGattServer(getApplicationContext(),
+            new BluetoothGattServerCallback() {});
+        mHandler = new Handler();
+        mAdvertiserStatus = 0;
+
+        mCallback = new BLEAdvertiseCallback();
+        mScannableCallback = new BLEAdvertiseCallback();
+        mUnscannableCallback = new BLEAdvertiseCallback();
+        mPowerLevel = new int[]{
+            AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
+            AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
+            AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
+            AdvertiseSettings.ADVERTISE_TX_POWER_HIGH};
+        mPowerCallback = new HashMap<Integer, AdvertiseCallback>();
+        for (int x : mPowerLevel) {
+            mPowerCallback.put(x, new BLEAdvertiseCallback());
+        }
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (intent != null) handleIntent(intent);
+        return START_NOT_STICKY;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mAdvertiser != null) {
+            stopAdvertiser();
+        }
+    }
+
+    private void stopAdvertiser() {
+        if (mAdvertiser == null) {
+            mAdvertiserStatus = 0;
+            return;
+        }
+        if ((mAdvertiserStatus & (1 << COMMAND_START_ADVERTISE)) > 0) {
+            mAdvertiser.stopAdvertising(mCallback);
+        }
+        if ((mAdvertiserStatus & (1 << COMMAND_START_POWER_LEVEL)) > 0) {
+            for (int t : mPowerLevel) {
+                mAdvertiser.stopAdvertising(mPowerCallback.get(t));
+            }
+        }
+        if ((mAdvertiserStatus & (1 << COMMAND_START_SCANNABLE)) > 0) {
+            mAdvertiser.stopAdvertising(mScannableCallback);
+        }
+        if ((mAdvertiserStatus & (1 << COMMAND_START_UNSCANNABLE)) > 0) {
+            mAdvertiser.stopAdvertising(mUnscannableCallback);
+        }
+        mAdvertiserStatus = 0;
+    }
+
+    private AdvertiseData generateAdvertiseData(UUID uuid, byte[] data) {
+        return new AdvertiseData.Builder()
+            .addManufacturerData(MANUFACTURER_TEST_ID, new byte[]{MANUFACTURER_TEST_ID, 0})
+            .addServiceData(new ParcelUuid(uuid), data)
+            .setIncludeTxPowerLevel(true)
+            .build();
+    }
+
+    private AdvertiseSettings generateSetting(int power) {
+        return new AdvertiseSettings.Builder()
+            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+            .setTxPowerLevel(power)
+            .setConnectable(false)
+            .build();
+    }
+
+    private void handleIntent(Intent intent) {
+        if (mBluetoothAdapter != null && !mBluetoothAdapter.isMultipleAdvertisementSupported()) {
+            showMessage("Multiple advertisement is not supported.");
+            sendBroadcast(new Intent(BLE_ADV_NOT_SUPPORT));
+            return;
+        } else if (mAdvertiser == null) {
+            showMessage("Cannot start advertising on this device.");
+            return;
+        }
+        int command = intent.getIntExtra(EXTRA_COMMAND, -1);
+        if (command >= 0) {
+            stopAdvertiser();
+            mAdvertiserStatus |= (1 << command);
+        }
+
+        switch (command) {
+            case COMMAND_START_ADVERTISE:
+                AdvertiseData data = generateAdvertiseData(PRIVACY_MAC_UUID, PRIVACY_MAC_DATA);
+                AdvertiseData response = generateAdvertiseData(SCAN_RESP_UUID, PRIVACY_RESPONSE);
+                AdvertiseSettings setting =
+                        generateSetting(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM);
+
+                mAdvertiser.startAdvertising(setting, data, response, mCallback);
+                sendBroadcast(new Intent(BLE_START_ADVERTISE));
+                break;
+            case COMMAND_STOP_ADVERTISE:
+                sendBroadcast(new Intent(BLE_STOP_ADVERTISE));
+                break;
+            case COMMAND_START_POWER_LEVEL:
+                for (int t : mPowerLevel) {
+                    AdvertiseData d =
+                            generateAdvertiseData(POWER_LEVEL_UUID, new byte[]{1, 5, (byte)t});
+                    AdvertiseSettings settings = generateSetting(t);
+                    mAdvertiser.startAdvertising(settings, d, mPowerCallback.get(t));
+                }
+                sendBroadcast(new Intent(BLE_START_POWER_LEVEL));
+                break;
+            case COMMAND_STOP_POWER_LEVEL:
+                sendBroadcast(new Intent(BLE_STOP_POWER_LEVEL));
+                break;
+            case COMMAND_START_SCANNABLE:
+                data = generateAdvertiseData(SCANNABLE_UUID, SCANNABLE_DATA);
+                setting = generateSetting(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM);
+
+                mAdvertiser.startAdvertising(setting, data, mScannableCallback);
+                sendBroadcast(new Intent(BLE_START_SCANNABLE));
+                break;
+            case COMMAND_START_UNSCANNABLE:
+                data = generateAdvertiseData(UNSCANNABLE_UUID, UNSCANNABLE_DATA);
+                setting = generateSetting(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM);
+
+                mAdvertiser.startAdvertising(setting, data, mUnscannableCallback);
+                sendBroadcast(new Intent(BLE_START_UNSCANNABLE));
+                break;
+            case COMMAND_STOP_SCANNABLE:
+                sendBroadcast(new Intent(BLE_STOP_SCANNABLE));
+                break;
+            case COMMAND_STOP_UNSCANNABLE:
+                sendBroadcast(new Intent(BLE_STOP_UNSCANNABLE));
+                break;
+            default:
+                showMessage("Unrecognized command: " + command);
+                break;
+        }
+    }
+
+    private void showMessage(final String msg) {
+        mHandler.post(new Runnable() {
+            public void run() {
+                Toast.makeText(BleAdvertiserService.this, msg, Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    private class BLEAdvertiseCallback extends AdvertiseCallback {
+        @Override
+        public void onStartFailure(int errorCode) {
+            Log.e(TAG, "fail. Error code: " + errorCode);
+        }
+
+        @Override
+        public void onStartSuccess(AdvertiseSettings setting) {
+            if (DEBUG) Log.d(TAG, "success.");
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserTestActivity.java
new file mode 100644
index 0000000..637ef71
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.ManifestTestListAdapter;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.os.Bundle;
+
+public class BleAdvertiserTestActivity extends PassFailButtons.TestListActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_list);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_advertiser_test_name, R.string.ble_advertiser_test_info, -1);
+
+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName()));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerHardwareScanFilterActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerHardwareScanFilterActivity.java
new file mode 100644
index 0000000..dd7e66c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerHardwareScanFilterActivity.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+public class BleScannerHardwareScanFilterActivity extends PassFailButtons.Activity {
+
+    private static final String TAG = "BleScannerHardwareScanFilter";
+
+    private ListView mScanResultListView;
+    private MapAdapter mAdapter;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_scanner_hardware_scan_filter);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_scanner_scan_filter_name,
+                         R.string.ble_scanner_scan_filter_info, -1);
+
+        mScanResultListView = (ListView)findViewById(R.id.ble_scan_result_list);
+        mAdapter = new MapAdapter();
+        mScanResultListView.setAdapter(mAdapter);
+
+        ((Button) findViewById(R.id.ble_scan_with_filter))
+                .setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        Intent intent = new Intent(BleScannerHardwareScanFilterActivity.this,
+                                BleScannerService.class);
+                        intent.putExtra(BleScannerService.EXTRA_COMMAND,
+                                BleScannerService.COMMAND_SCAN_WITH_FILTER);
+                        startService(intent);
+                    }
+                });
+
+        ((Button) findViewById(R.id.ble_scan_without_filter))
+                .setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        Intent intent = new Intent(BleScannerHardwareScanFilterActivity.this,
+                                BleScannerService.class);
+                        intent.putExtra(BleScannerService.EXTRA_COMMAND,
+                                BleScannerService.COMMAND_SCAN_WITHOUT_FILTER);
+                        startService(intent);
+                    }
+                });
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BleScannerService.BLE_SCAN_RESULT);
+        registerReceiver(onBroadcast, filter);
+    }
+
+
+    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case BleScannerService.BLE_SCAN_RESULT:
+                    String uuid = intent.getStringExtra(BleScannerService.EXTRA_UUID);
+                    String data = intent.getStringExtra(BleScannerService.EXTRA_DATA);
+                    if (data != null) {
+                        mAdapter.addItem(uuid + " : " + data);
+                    }
+                    break;
+            }
+        }
+    };
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(onBroadcast);
+    }
+
+    private void stop() {
+        stopService(new Intent(this, BleScannerService.class));
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stop();
+    }
+
+    public class MapAdapter extends BaseAdapter {
+        private Map<String, Integer> mData;
+        private ArrayList<String> mKeys;
+        public MapAdapter() {
+            mData = new HashMap<>();
+            mKeys = new ArrayList<>();
+        }
+
+        @Override
+        public int getCount() {
+            return mData.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return mData.get(mKeys.get(position));
+        }
+
+        @Override
+        public long getItemId(int arg0) {
+            return arg0;
+        }
+
+        public void addItem(String key) {
+            if (!mData.containsKey(key)) {
+                mKeys.add(key);
+                mData.put(key, new Integer(1));
+            } else {
+                mData.put(key, mData.get(key) + 1);
+            }
+            this.notifyDataSetChanged();
+        }
+
+        @Override
+        public View getView(int pos, View view, ViewGroup parent) {
+            if (view == null) {
+                view = LayoutInflater.from(parent.getContext())
+                    .inflate(android.R.layout.simple_list_item_2, parent, false);
+            }
+            String key = mKeys.get(pos);
+            String value = getItem(pos).toString();
+            TextView text1 = (TextView) view.findViewById(android.R.id.text1);
+            TextView text2 = (TextView) view.findViewById(android.R.id.text2);
+            text1.setText(key);
+            text2.setText(value);
+            return view;
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
new file mode 100644
index 0000000..a6489c1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.lang.Math;
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+
+import android.bluetooth.le.AdvertiseSettings;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.util.Log;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class BleScannerPowerLevelActivity extends PassFailButtons.Activity {
+
+    private static final String TAG = "BleScannerPowerLevel";
+
+    private Map<Integer, TextView> mMacText;
+    private Map<Integer, TextView> mCountText;
+    private Map<Integer, TextView> mRssiText;
+    private Map<Integer, TextView> mSetPowerText;
+    private Map<Integer, Integer> mCount;
+    private int[] mPowerLevel;
+
+    private TextView mTimerText;
+    private CountDownTimer mTimer;
+    private static final long REFRESH_MAC_TIME = 930000; // 15.5 min
+
+    private static final int[] POWER_DBM = {-21, -15, -7, 1, 9};
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ble_scanner_power_level);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_power_level_name,
+                         R.string.ble_power_level_info, -1);
+
+        mTimerText = (TextView)findViewById(R.id.ble_timer);
+        mTimer = new CountDownTimer(REFRESH_MAC_TIME, 1000) {
+            @Override
+            public void onTick(long millis) {
+                int min = (int)millis / 60000;
+                int sec = ((int)millis / 1000) % 60;
+                mTimerText.setText(min + ":" + sec);
+            }
+
+            @Override
+            public void onFinish() {
+                mTimerText.setTextColor(getResources().getColor(R.color.red));
+                mTimerText.setText("Time is up!");
+            }
+        };
+
+        mRssiText = new HashMap<Integer, TextView>();
+        mCountText = new HashMap<Integer, TextView>();
+        mCount = null;
+        mMacText = new HashMap<Integer, TextView>();
+        mSetPowerText = new HashMap<Integer, TextView>();
+        mPowerLevel = new int[]{AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
+            AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
+            AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
+            AdvertiseSettings.ADVERTISE_TX_POWER_HIGH};
+
+        mMacText.put(AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
+            (TextView)findViewById(R.id.ble_ultra_low_mac));
+        mMacText.put(AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
+            (TextView)findViewById(R.id.ble_low_mac));
+        mMacText.put(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
+            (TextView)findViewById(R.id.ble_medium_mac));
+        mMacText.put(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH,
+            (TextView)findViewById(R.id.ble_high_mac));
+
+        mCountText.put(AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
+            (TextView)findViewById(R.id.ble_ultra_low_count));
+        mCountText.put(AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
+            (TextView)findViewById(R.id.ble_low_count));
+        mCountText.put(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
+            (TextView)findViewById(R.id.ble_medium_count));
+        mCountText.put(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH,
+            (TextView)findViewById(R.id.ble_high_count));
+
+        mRssiText.put(AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
+            (TextView)findViewById(R.id.ble_ultra_low_rssi));
+        mRssiText.put(AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
+            (TextView)findViewById(R.id.ble_low_rssi));
+        mRssiText.put(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
+            (TextView)findViewById(R.id.ble_medium_rssi));
+        mRssiText.put(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH,
+            (TextView)findViewById(R.id.ble_high_rssi));
+
+        mSetPowerText.put(AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
+            (TextView)findViewById(R.id.ble_ultra_low_set_power));
+        mSetPowerText.put(AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
+            (TextView)findViewById(R.id.ble_low_set_power));
+        mSetPowerText.put(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
+            (TextView)findViewById(R.id.ble_medium_set_power));
+        mSetPowerText.put(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH,
+            (TextView)findViewById(R.id.ble_high_set_power));
+
+        Intent intent = new Intent(this, BleScannerService.class);
+        intent.putExtra(BleScannerService.EXTRA_COMMAND, BleScannerService.COMMAND_POWER_LEVEL);
+        startService(intent);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BleScannerService.BLE_POWER_LEVEL);
+        filter.addAction(BleScannerService.BLE_PRIVACY_NEW_MAC_RECEIVE);
+        registerReceiver(onBroadcast, filter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(onBroadcast);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopService(new Intent(this, BleScannerService.class));
+    }
+
+    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case BleScannerService.BLE_POWER_LEVEL:
+                    int powerLevelBit = intent.getIntExtra(
+                            BleScannerService.EXTRA_POWER_LEVEL_BIT, -1);
+                    int powerLevel = intent.getIntExtra(BleScannerService.EXTRA_POWER_LEVEL, -2);
+                    if (powerLevelBit < 0 || powerLevelBit > 3) {
+                        Toast.makeText(context, "Invalid power level", Toast.LENGTH_SHORT).show();
+                        break;
+                    }
+
+                    if (mCount == null) {
+                        mCount = new HashMap<Integer, Integer>();
+                        for (int i : mPowerLevel) {
+                            mCount.put(i, 0);
+                        }
+                        mTimer.start();
+                    }
+                    Integer t = mCount.get(powerLevelBit) + 1;
+                    mCount.put(powerLevelBit, t);
+                    mCountText.get(powerLevelBit).setText(t.toString());
+
+                    mMacText.get(powerLevelBit)
+                        .setText(intent.getStringExtra(BleScannerService.EXTRA_MAC_ADDRESS));
+                    mRssiText.get(powerLevelBit)
+                        .setText(intent.getStringExtra(BleScannerService.EXTRA_RSSI));
+                    if (Math.abs(POWER_DBM[powerLevelBit] - powerLevel) < 2) {
+                        mSetPowerText.get(powerLevelBit).setText("Valid power level");
+                    } else {
+                        mSetPowerText.get(powerLevelBit)
+                            .setText("Unknown BLe advertise tx power: " + powerLevel);
+                    }
+                    break;
+                case BleScannerService.BLE_PRIVACY_NEW_MAC_RECEIVE:
+                     Toast.makeText(context, "New MAC address detected", Toast.LENGTH_SHORT)
+                            .show();
+                     mTimerText.setTextColor(getResources().getColor(R.color.green));
+                     mTimerText.append("   Get new MAC address.");
+                     mTimer.cancel();
+                     getPassButton().setEnabled(true);
+                     break;
+            }
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
new file mode 100644
index 0000000..d3d96ac
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanSettings;
+import android.bluetooth.le.ScanRecord;
+import android.bluetooth.le.ScanResult;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class BleScannerService extends Service {
+
+    public static final boolean DEBUG = true;
+    public static final String TAG = "BleScannerService";
+
+    public static final int COMMAND_POWER_LEVEL = 1;
+    public static final int COMMAND_SCAN_WITH_FILTER = 2;
+    public static final int COMMAND_SCAN_WITHOUT_FILTER = 3;
+
+    public static final String BLE_PRIVACY_NEW_MAC_RECEIVE =
+            "com.android.cts.verifier.bluetooth.BLE_PRIVACY_NEW_MAC_RECEIVE";
+    public static final String BLE_MAC_ADDRESS =
+            "com.android.cts.verifier.bluetooth.BLE_MAC_ADDRESS";
+    public static final String BLE_POWER_LEVEL =
+            "com.android.cts.verifier.bluetooth.BLE_POWER_LEVEL";
+    public static final String BLE_SCAN_RESP =
+            "com.android.cts.verifier.bluetooth.BLE_SCAN_RESP";
+    public static final String BLE_SCAN_RESULT =
+            "com.android.cts.verifier.bluetooth.BLE_SCAN_RESULT";
+
+    public static final String EXTRA_COMMAND =
+            "com.google.cts.verifier.bluetooth.EXTRA_COMMAND";
+    public static final String EXTRA_MAC_ADDRESS =
+            "com.google.cts.verifier.bluetooth.EXTRA_MAC_ADDRESS";
+    public static final String EXTRA_RSSI =
+            "com.google.cts.verifier.bluetooth.EXTRA_RSSI";
+    public static final String EXTRA_POWER_LEVEL =
+            "com.google.cts.verifier.bluetooth.EXTRA_POWER_LEVEL";
+    public static final String EXTRA_POWER_LEVEL_BIT =
+            "com.google.cts.verifier.bluetooth.EXTRA_POWER_LEVEL_BIT";
+    public static final String EXTRA_UUID =
+            "com.google.cts.verifier.bluetooth.EXTRA_UUID";
+    public static final String EXTRA_DATA =
+            "com.google.cts.verifier.bluetooth.EXTRA_DATA";
+
+    private static final byte MANUFACTURER_TEST_ID = (byte)0x07;
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothAdapter mAdapter;
+    private BluetoothLeScanner mScanner;
+    private ScanCallback mCallback;
+    private Handler mHandler;
+    private String mOldMac;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mCallback = new BLEScanCallback();
+        mHandler = new Handler();
+        mOldMac = null;
+
+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mAdapter = mBluetoothManager.getAdapter();
+        mScanner = mAdapter.getBluetoothLeScanner();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (mScanner != null) {
+            List<ScanFilter> filters = new ArrayList<ScanFilter>();
+            ScanSettings.Builder settingBuilder = new ScanSettings.Builder();
+
+            int command = intent.getIntExtra(EXTRA_COMMAND, -1);
+            switch (command) {
+                case COMMAND_POWER_LEVEL:
+                    filters.add(new ScanFilter.Builder()
+                        .setManufacturerData(MANUFACTURER_TEST_ID,
+                            new byte[]{MANUFACTURER_TEST_ID, 0})
+                        .setServiceData(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID),
+                            BleAdvertiserService.POWER_LEVEL_DATA,
+                            BleAdvertiserService.POWER_LEVEL_MASK)
+                        .build());
+                    settingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
+                    break;
+                case COMMAND_SCAN_WITH_FILTER:
+                    mScanner.stopScan(mCallback);
+                    filters.add(new ScanFilter.Builder()
+                        .setManufacturerData(MANUFACTURER_TEST_ID,
+                            new byte[]{MANUFACTURER_TEST_ID, 0})
+                        .setServiceData(new ParcelUuid(BleAdvertiserService.SCANNABLE_UUID),
+                            BleAdvertiserService.SCANNABLE_DATA)
+                        .build());
+                    settingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
+                    break;
+                case COMMAND_SCAN_WITHOUT_FILTER:
+                    mScanner.stopScan(mCallback);
+                    settingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
+                    break;
+            }
+            mOldMac = null;
+            mScanner.startScan(filters, settingBuilder.build(), mCallback);
+        }
+        return START_NOT_STICKY;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mScanner.stopScan(mCallback);
+    }
+
+    private void showMessage(final String msg) {
+        mHandler.post(new Runnable() {
+            public void run() {
+                Toast.makeText(BleScannerService.this, msg, Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    private class BLEScanCallback extends ScanCallback {
+        @Override
+        public void onScanResult(int callBackType, ScanResult result) {
+            if (callBackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
+                Log.e(TAG, "onScanResult fail. callBackType is not CALLBACK_TYPE_ALL_MATCHES");
+                return;
+            }
+
+            ScanRecord record = result.getScanRecord();
+            String mac = result.getDevice().getAddress();
+            Map<ParcelUuid, byte[]> serviceData = record.getServiceData();
+
+            if (serviceData.get(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID)) != null) {
+                byte[] data =
+                        serviceData.get(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID));
+                if (data.length == 3) {
+                    Intent powerIntent = new Intent(BLE_POWER_LEVEL);
+                    powerIntent.putExtra(EXTRA_MAC_ADDRESS, result.getDevice().getAddress());
+                    powerIntent.putExtra(EXTRA_POWER_LEVEL, record.getTxPowerLevel());
+                    powerIntent.putExtra(EXTRA_RSSI, new Integer(result.getRssi()).toString());
+                    powerIntent.putExtra(EXTRA_POWER_LEVEL_BIT, (int)data[2]);
+                    sendBroadcast(powerIntent);
+
+                    // Check privacy mac.
+                    if (data[2] == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) {
+                        String newMac = result.getDevice().getAddress();
+                        if (mOldMac == null) {
+                            mOldMac = newMac;
+                        } else if (!mOldMac.equals(mac)) {
+                            mOldMac = newMac;
+                            Intent newIntent = new Intent(BLE_PRIVACY_NEW_MAC_RECEIVE);
+                            sendBroadcast(newIntent);
+                        }
+                    }
+                }
+            }
+
+            if (serviceData.get(new ParcelUuid(BleAdvertiserService.SCAN_RESP_UUID)) != null) {
+                Intent responseIntent = new Intent(BLE_SCAN_RESP);
+                sendBroadcast(responseIntent);
+            }
+
+            byte[] data = null;
+            String uuid = "";
+            if (serviceData.containsKey(new ParcelUuid(BleAdvertiserService.SCANNABLE_UUID))) {
+                uuid = BleAdvertiserService.SCANNABLE_UUID.toString();
+                data = serviceData.get(new ParcelUuid(BleAdvertiserService.SCANNABLE_UUID));
+            }
+            if (serviceData.containsKey(new ParcelUuid(BleAdvertiserService.UNSCANNABLE_UUID))) {
+                uuid = BleAdvertiserService.UNSCANNABLE_UUID.toString();
+                data = serviceData.get(new ParcelUuid(BleAdvertiserService.UNSCANNABLE_UUID));
+            }
+            if (uuid.length() > 0) {
+                Intent scanIntent = new Intent(BLE_SCAN_RESULT);
+                scanIntent.putExtra(EXTRA_UUID, uuid);
+                String dataStr = "{";
+                for (byte x : data) {
+                    dataStr = dataStr + " " + x;
+                }
+                dataStr = dataStr + "}";
+                scanIntent.putExtra(EXTRA_DATA, dataStr);
+                sendBroadcast(scanIntent);
+            }
+        }
+
+        public void onScanFailed(int errorCode) {
+            Log.e(TAG, "Scan fail. Error code: " + new Integer(errorCode).toString());
+        }
+
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerTestActivity.java
new file mode 100644
index 0000000..1f54917
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.ManifestTestListAdapter;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.os.Bundle;
+
+public class BleScannerTestActivity extends PassFailButtons.TestListActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_list);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.ble_scanner_test_name,
+                         R.string.ble_scanner_test_info, -1);
+        setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName()));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
index 5606041..91b3a6c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
@@ -65,6 +65,8 @@
             "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST";
     public static final String BLE_EXECUTE_WRITE =
             "com.android.cts.verifier.bluetooth.BLE_EXECUTE_WRITE";
+    public static final String BLE_OPEN_FAIL =
+            "com.android.cts.verifier.bluetooth.BLE_OPEN_FAIL";
 
     private static final UUID SERVICE_UUID =
             UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
@@ -90,11 +92,16 @@
         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
         mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
         mService = createService();
-        mGattServer.addService(mService);
+        if (mGattServer != null) {
+            mGattServer.addService(mService);
+        }
         mDevice = null;
         mReliableWriteValue = null;
 
         mHandler = new Handler();
+        if (mGattServer == null) {
+            notifyOpenFail();
+        }
     }
 
     @Override
@@ -110,6 +117,9 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+        if (mGattServer == null) {
+           return;
+        }
         if (mDevice != null) mGattServer.cancelConnection(mDevice);
         mGattServer.close();
     }
@@ -126,6 +136,12 @@
         descriptor.setValue(writeValue.getBytes());
     }
 
+    private void notifyOpenFail() {
+        if (DEBUG) Log.d(TAG, "notifyOpenFail");
+        Intent intent = new Intent(BLE_OPEN_FAIL);
+        sendBroadcast(intent);
+    }
+
     private void notifyConnected() {
         if (DEBUG) Log.d(TAG, "notifyConnected");
         Intent intent = new Intent(BLE_SERVER_CONNECTED);
@@ -216,6 +232,10 @@
         TimerTask task = new TimerTask() {
             @Override
             public void run() {
+                if (mGattServer == null) {
+                    if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                    return;
+                }
                 BluetoothGattCharacteristic characteristic =
                         mService.getCharacteristic(UPDATE_CHARACTERISTIC_UUID);
                 if (characteristic == null) return;
@@ -268,7 +288,11 @@
 
         @Override
         public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
-                            int offset, BluetoothGattCharacteristic characteristic) {
+                int offset, BluetoothGattCharacteristic characteristic) {
+            if (mGattServer == null) {
+                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                return;
+            }
             if (DEBUG) Log.d(TAG, "onCharacteristicReadRequest()");
 
             notifyCharacteristicReadRequest();
@@ -278,9 +302,13 @@
 
         @Override
         public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
-                                                 BluetoothGattCharacteristic characteristic,
-                                                 boolean preparedWrite, boolean responseNeeded,
-                                                 int offset, byte[] value) {
+                BluetoothGattCharacteristic characteristic,
+                boolean preparedWrite, boolean responseNeeded,
+                int offset, byte[] value) {
+            if (mGattServer == null) {
+                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                return;
+            }
             if (DEBUG) Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);
 
             notifyCharacteristicWriteRequest();
@@ -293,7 +321,11 @@
 
         @Override
         public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
-                                            int offset, BluetoothGattDescriptor descriptor) {
+                int offset, BluetoothGattDescriptor descriptor) {
+            if (mGattServer == null) {
+                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                return;
+            }
             if (DEBUG) Log.d(TAG, "onDescriptorReadRequest(): (descriptor == getDescriptor())="
                                   + (descriptor == getDescriptor()));
 
@@ -304,9 +336,13 @@
 
         @Override
         public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
-                                             BluetoothGattDescriptor descriptor,
-                                             boolean preparedWrite, boolean responseNeeded,
-                                             int offset,  byte[] value) {
+                BluetoothGattDescriptor descriptor,
+                boolean preparedWrite, boolean responseNeeded,
+                int offset,  byte[] value) {
+            if (mGattServer == null) {
+                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                return;
+            }
             if (DEBUG) Log.d(TAG, "onDescriptorWriteRequest(): (descriptor == getDescriptor())="
                                   + (descriptor == getDescriptor()));
 
@@ -318,6 +354,10 @@
 
         @Override
         public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
+            if (mGattServer == null) {
+                if (DEBUG) Log.d(TAG, "GattServer is null, return");
+                return;
+            }
             if (DEBUG) Log.d(TAG, "onExecuteWrite");
             if (execute) {
                 notifyExecuteWrite();
@@ -326,4 +366,5 @@
             }
         }
     };
-}
\ No newline at end of file
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerStartActivity.java
index ec31fde..e8e35d5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerStartActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerStartActivity.java
@@ -34,10 +34,10 @@
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
+import android.widget.Toast;
 
 public class BleServerStartActivity extends PassFailButtons.Activity {
 
-    private List<Test> mTestList;
     private TestAdapter mTestAdapter;
     private int mAllPassed;
 
@@ -50,9 +50,7 @@
                          R.string.ble_server_start_info, -1);
         getPassButton().setEnabled(false);
 
-        mTestList = setupTestList();
-        mTestAdapter = new TestAdapter(this, mTestList);
-
+        mTestAdapter = new TestAdapter(this, setupTestList());
         ListView listView = (ListView) findViewById(R.id.ble_server_tests);
         listView.setAdapter(mTestAdapter);
 
@@ -73,6 +71,7 @@
         filter.addAction(BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST);
         filter.addAction(BleServerService.BLE_EXECUTE_WRITE);
         filter.addAction(BleServerService.BLE_SERVER_DISCONNECTED);
+        filter.addAction(BleServerService.BLE_OPEN_FAIL);
         registerReceiver(onBroadcast, filter);
     }
 
@@ -88,109 +87,59 @@
         stopService(new Intent(this, BleServerService.class));
     }
 
-    private List<Test> setupTestList() {
-        ArrayList<Test> testList = new ArrayList<Test>();
-        testList.add(new Test(R.string.ble_server_add_service));
-        testList.add(new Test(R.string.ble_server_receiving_connect));
-        testList.add(new Test(R.string.ble_server_read_characteristic));
-        testList.add(new Test(R.string.ble_server_write_characteristic));
-        testList.add(new Test(R.string.ble_server_read_descriptor));
-        testList.add(new Test(R.string.ble_server_write_descriptor));
-        testList.add(new Test(R.string.ble_server_reliable_write));
-        testList.add(new Test(R.string.ble_server_receiving_disconnect));
+    private List<Integer> setupTestList() {
+        ArrayList<Integer> testList = new ArrayList<Integer>();
+        testList.add(R.string.ble_server_add_service);
+        testList.add(R.string.ble_server_receiving_connect);
+        testList.add(R.string.ble_server_read_characteristic);
+        testList.add(R.string.ble_server_write_characteristic);
+        testList.add(R.string.ble_server_read_descriptor);
+        testList.add(R.string.ble_server_write_descriptor);
+        testList.add(R.string.ble_server_reliable_write);
+        testList.add(R.string.ble_server_receiving_disconnect);
         return testList;
     }
 
-    class Test {
-        private boolean passed;
-        private int instructions;
-
-        private Test(int instructions) {
-            passed = false;
-            this.instructions = instructions;
-        }
-    }
-
     private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (action == BleServerService.BLE_SERVICE_ADDED) {
-                mTestList.get(0).passed = true;
+                mTestAdapter.setTestPass(0);
                 mAllPassed |= 0x01;
             } else if (action == BleServerService.BLE_SERVER_CONNECTED) {
-                mTestList.get(1).passed = true;
+                mTestAdapter.setTestPass(1);
                 mAllPassed |= 0x02;
             } else if (action == BleServerService.BLE_CHARACTERISTIC_READ_REQUEST) {
-                mTestList.get(2).passed = true;
+                mTestAdapter.setTestPass(2);
                 mAllPassed |= 0x04;
             } else if (action == BleServerService.BLE_CHARACTERISTIC_WRITE_REQUEST) {
-                mTestList.get(3).passed = true;
+                mTestAdapter.setTestPass(3);
                 mAllPassed |= 0x08;
             } else if (action == BleServerService.BLE_DESCRIPTOR_READ_REQUEST) {
-                mTestList.get(4).passed = true;
+                mTestAdapter.setTestPass(4);
                 mAllPassed |= 0x10;
             } else if (action == BleServerService.BLE_DESCRIPTOR_WRITE_REQUEST) {
-                mTestList.get(5).passed = true;
+                mTestAdapter.setTestPass(5);
                 mAllPassed |= 0x20;
             } else if (action == BleServerService.BLE_EXECUTE_WRITE) {
-                mTestList.get(6).passed = true;
+                mTestAdapter.setTestPass(6);
                 mAllPassed |= 0x40;
             } else if (action == BleServerService.BLE_SERVER_DISCONNECTED) {
-                mTestList.get(7).passed = true;
+                mTestAdapter.setTestPass(7);
                 mAllPassed |= 0x80;
+            } else if (action == BleServerService.BLE_OPEN_FAIL) {
+                setTestResultAndFinish(false);
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        Toast.makeText(BleServerStartActivity.this, "Cannot open GattService",
+                                Toast.LENGTH_SHORT).show();
+                    }
+                });
             }
             mTestAdapter.notifyDataSetChanged();
             if (mAllPassed == 0xFF) getPassButton().setEnabled(true);
         }
     };
-
-    class TestAdapter extends BaseAdapter {
-        Context context;
-        List<Test> tests;
-        LayoutInflater inflater;
-
-        public TestAdapter(Context context, List<Test> tests) {
-            this.context = context;
-            inflater = LayoutInflater.from(context);
-            this.tests = tests;
-        }
-
-        @Override
-        public int getCount() {
-            return tests.size();
-        }
-
-        @Override
-        public Object getItem(int position) {
-            return tests.get(position);
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            ViewGroup vg;
-
-            if (convertView != null) {
-                vg = (ViewGroup) convertView;
-            } else {
-                vg = (ViewGroup) inflater.inflate(R.layout.ble_server_start_item, null);
-            }
-
-            Test test = tests.get(position);
-            if (test.passed) {
-                ((ImageView) vg.findViewById(R.id.status)).setImageResource(R.drawable.fs_good);
-            } else {
-                ((ImageView) vg.findViewById(R.id.status)).
-                                setImageResource(R.drawable.fs_indeterminate);
-            }
-            ((TextView) vg.findViewById(R.id.instructions)).setText(test.instructions);
-
-            return vg;
-        }
-    }
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestAdapter.java
new file mode 100644
index 0000000..631fe36
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestAdapter.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+class TestAdapter extends BaseAdapter {
+    Context context;
+    List<Test> tests;
+    LayoutInflater inflater;
+
+    private class Test {
+        private boolean mPassed;
+        private final int mInstructions;
+
+        protected Test(int instructions) {
+            this.mPassed = false;
+            this.mInstructions = instructions;
+        }
+    }
+
+    public TestAdapter(Context context, List<Integer> testInstructions) {
+        this.context = context;
+        inflater = LayoutInflater.from(context);
+        this.tests = new ArrayList<Test>();
+        for (int t : testInstructions) {
+            this.tests.add(new Test(t));
+        }
+    }
+
+    @Override
+    public int getCount() {
+        return tests.size();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return tests.get(position);
+    }
+
+    public void setTestPass(int position) {
+        tests.get(position).mPassed = true;
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        ViewGroup vg;
+
+        if (convertView != null) {
+            vg = (ViewGroup) convertView;
+        } else {
+            vg = (ViewGroup) inflater.inflate(R.layout.ble_server_start_item, null);
+        }
+
+        Test test = tests.get(position);
+        if (test.mPassed) {
+            ((ImageView) vg.findViewById(R.id.status)).setImageResource(R.drawable.fs_good);
+        } else {
+            ((ImageView) vg.findViewById(R.id.status)).
+                            setImageResource(R.drawable.fs_indeterminate);
+        }
+        ((TextView) vg.findViewById(R.id.instructions)).setText(test.mInstructions);
+
+        return vg;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
old mode 100644
new mode 100755
index d68d1da..d325b65
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
@@ -18,7 +18,6 @@
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.graphics.Bitmap;
 import android.graphics.Color;
@@ -34,19 +33,22 @@
 import android.os.Handler;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.Surface;
 import android.view.TextureView;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.Spinner;
+import android.widget.Toast;
 
 import java.io.IOException;
-import java.lang.InterruptedException;
 import java.lang.Math;
-import java.lang.Thread;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Comparator;
 import java.util.List;
 import java.util.TreeSet;
@@ -100,11 +102,22 @@
     private TreeSet<String> mTestedCombinations = new TreeSet<String>();
     private TreeSet<String> mUntestedCombinations = new TreeSet<String>();
 
+    private int mAllCombinationsSize = 0;
+
+    // Menu to show the test progress
+    private static final int MENU_ID_PROGRESS = Menu.FIRST + 1;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.cf_main);
+
+        mAllCombinationsSize = calcAllCombinationsSize();
+
+        // disable "Pass" button until all combinations are tested
+        setPassButtonEnabled(false);
+
         setPassFailButtonClickListeners();
         setInfoResources(R.string.camera_format, R.string.cf_info, -1);
 
@@ -161,6 +174,36 @@
     }
 
     @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        menu.add(Menu.NONE, MENU_ID_PROGRESS, Menu.NONE, "Current Progress");
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean ret = true;
+        switch (item.getItemId()) {
+        case MENU_ID_PROGRESS:
+            showCombinationsDialog();
+            ret = true;
+            break;
+        default:
+            ret = super.onOptionsItemSelected(item);
+            break;
+        }
+        return ret;
+    }
+
+    private void showCombinationsDialog() {
+        AlertDialog.Builder builder =
+                new AlertDialog.Builder(CameraFormatsActivity.this);
+        builder.setMessage(getTestDetails())
+                .setTitle("Current Progress")
+                .setPositiveButton("OK", null);
+        builder.show();
+    }
+
+    @Override
     public void onResume() {
         super.onResume();
 
@@ -299,9 +342,10 @@
             new ArrayAdapter<String>(
                 this, R.layout.cf_format_list_item, availableSizeNames));
 
-        // Get preview formats
+        // Get preview formats, removing duplicates
 
-        mPreviewFormats =  p.getSupportedPreviewFormats();
+        HashSet<Integer> formatSet = new HashSet<>(p.getSupportedPreviewFormats());
+        mPreviewFormats = new ArrayList<Integer>(formatSet);
 
         String[] availableFormatNames = new String[mPreviewFormats.size()];
         for (int i = 0; i < mPreviewFormats.size(); i++) {
@@ -526,6 +570,12 @@
                             + "\n";
                     mUntestedCombinations.remove(combination);
                     mTestedCombinations.add(combination);
+
+                    displayToast(combination.replace("\n", ""));
+
+                    if (mTestedCombinations.size() == mAllCombinationsSize) {
+                        setPassButtonEnabled(true);
+                    }
                 }
             }
             mProcessInProgress = false;
@@ -533,6 +583,36 @@
 
     }
 
+    private void setPassButtonEnabled(boolean enabled) {
+        ImageButton pass_button = (ImageButton) findViewById(R.id.pass_button);
+        pass_button.setEnabled(enabled);
+    }
+
+    private int calcAllCombinationsSize() {
+        int allCombinationsSize = 0;
+        int numCameras = Camera.getNumberOfCameras();
+
+        for (int i = 0; i<numCameras; i++) {
+            // must release a Camera object before a new Camera object is created
+            shutdownCamera();
+
+            mCamera = Camera.open(i);
+            Camera.Parameters p = mCamera.getParameters();
+
+            HashSet<Integer> formatSet = new HashSet<>(p.getSupportedPreviewFormats());
+
+            allCombinationsSize +=
+                    p.getSupportedPreviewSizes().size() *   // resolutions
+                    formatSet.size();  // unique formats
+        }
+
+        return allCombinationsSize;
+    }
+
+    private void displayToast(String combination) {
+        Toast.makeText(this, "\"" + combination + "\"\n" + " has been tested.", Toast.LENGTH_LONG).show();
+    }
+
     public void onPreviewFrame(byte[] data, Camera camera) {
         if (mProcessInProgress || mState != STATE_PREVIEW) return;
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
index 05013ed..e5af6ba 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
@@ -30,6 +30,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.util.Log;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
@@ -68,7 +69,7 @@
     private List<SelectableResolution> mSupportedResolutions;
     private ArrayAdapter<SelectableResolution> mAdapter;
 
-    private int mCameraId;
+    private SelectableResolution mSelectedResolution;
     private Camera mCamera;
     private Size mSurfaceSize;
     private boolean mCameraInitialized = false;
@@ -76,6 +77,8 @@
     private int mResolutionSpinnerIndex = -1;
     private WakeLock mWakeLock;
     private long shutterStartTime;
+    private int mPreviewOrientation;
+    private int mJpegOrientation;
 
     private ArrayList<Integer> mPreviewSizeCamerasToProcess = new ArrayList<Integer>();
 
@@ -164,18 +167,13 @@
                     AdapterView<?> parent, View view, int position, long id) {
                 if (mSupportedResolutions != null) {
                     SelectableResolution resolution = mSupportedResolutions.get(position);
-
-                    switchToCamera(resolution.cameraId, false);
-
-                    Camera.Parameters params = mCamera.getParameters();
-                    params.setPictureSize(resolution.width, resolution.height);
-                    mCamera.setParameters(params);
+                    switchToCamera(resolution, false);
 
                     // It should be guaranteed that the FOV is correctly updated after setParameters().
                     mReportedFovPrePictureTaken = mCamera.getParameters().getHorizontalViewAngle();
 
                     mResolutionSpinnerIndex = position;
-                    initializeCamera();
+                    startPreview();
                 }
             }
 
@@ -375,7 +373,7 @@
                     public void onCancel(DialogInterface arg0) {
                         // User cancelled preview size selection.
                         mPreviewSizes = null;
-                        switchToCamera(mCameraId, true);
+                        switchToCamera(mSelectedResolution, true);
                     }
                 }).
                 setSingleChoiceItems(choices, 0, new DialogInterface.OnClickListener() {
@@ -388,7 +386,7 @@
 
                         if (mPreviewSizeCamerasToProcess.isEmpty()) {
                             // We're done, re-initialize camera.
-                            switchToCamera(mCameraId, true);
+                            switchToCamera(mSelectedResolution, true);
                         } else {
                             // Process other cameras.
                             showNextDialogToChoosePreviewSize();
@@ -399,6 +397,10 @@
     }
 
     private void initializeCamera() {
+        initializeCamera(true);
+    }
+
+    private void initializeCamera(boolean startPreviewAfterInit) {
         if (mCamera == null || mSurfaceHolder.getSurface() == null) {
             return;
         }
@@ -410,38 +412,43 @@
             Toast.makeText(this, t.getMessage(), Toast.LENGTH_LONG).show();
             return;
         }
+
+        calculateOrientations(this, mSelectedResolution.cameraId, mCamera);
         Camera.Parameters params = setCameraParams(mCamera);
 
         // Either use chosen preview size for current camera or automatically
         // choose preview size based on view dimensions.
-        Size selectedPreviewSize = (mPreviewSizes != null) ? mPreviewSizes[mCameraId] :
+        Size selectedPreviewSize = (mPreviewSizes != null) ? mPreviewSizes[mSelectedResolution.cameraId] :
             getBestPreviewSize(mSurfaceSize.width, mSurfaceSize.height, params);
         if (selectedPreviewSize != null) {
             params.setPreviewSize(selectedPreviewSize.width, selectedPreviewSize.height);
             mCamera.setParameters(params);
             mCameraInitialized = true;
         }
-        startPreview();
+
+        if (startPreviewAfterInit) {
+          startPreview();
+        }
     }
 
     private void startPreview() {
         if (mCameraInitialized && mCamera != null) {
+            mCamera.setDisplayOrientation(mPreviewOrientation);
             mCamera.startPreview();
             mPreviewActive = true;
         }
     }
 
-    private void switchToCamera(int cameraId, boolean initializeCamera) {
+    private void switchToCamera(SelectableResolution resolution, boolean startPreview) {
         if (mCamera != null) {
             mCamera.stopPreview();
             mCamera.release();
         }
-        mCameraId = cameraId;
-        mCamera = Camera.open(cameraId);
 
-        if (initializeCamera){
-          initializeCamera();
-        }
+        mSelectedResolution = resolution;
+        mCamera = Camera.open(mSelectedResolution.cameraId);
+
+        initializeCamera(startPreview);
     }
 
     /**
@@ -470,14 +477,16 @@
      * Set the common camera parameters on the given camera and returns the
      * parameter object for further modification, if needed.
      */
-    private static Camera.Parameters setCameraParams(Camera camera) {
+    private Camera.Parameters setCameraParams(Camera camera) {
         // The picture size is taken and set from the spinner selection
         // callback.
         Camera.Parameters params = camera.getParameters();
         params.setJpegThumbnailSize(0, 0);
         params.setJpegQuality(100);
+        params.setRotation(mJpegOrientation);
         params.setFocusMode(getFocusMode(camera));
         params.setZoom(0);
+        params.setPictureSize(mSelectedResolution.width, mSelectedResolution.height);
         return params;
     }
 
@@ -501,4 +510,28 @@
         }
         return result;
     }
+
+    private void calculateOrientations(Activity activity,
+            int cameraId, android.hardware.Camera camera) {
+        android.hardware.Camera.CameraInfo info =
+                new android.hardware.Camera.CameraInfo();
+        android.hardware.Camera.getCameraInfo(cameraId, info);
+        int rotation = activity.getWindowManager().getDefaultDisplay()
+                .getRotation();
+        int degrees = 0;
+        switch (rotation) {
+            case Surface.ROTATION_0: degrees = 0; break;
+            case Surface.ROTATION_90: degrees = 90; break;
+            case Surface.ROTATION_180: degrees = 180; break;
+            case Surface.ROTATION_270: degrees = 270; break;
+        }
+
+        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+            mJpegOrientation = (info.orientation + degrees) % 360;
+            mPreviewOrientation = (360 - mJpegOrientation) % 360;  // compensate the mirror
+        } else {  // back-facing
+            mJpegOrientation = (info.orientation - degrees + 360) % 360;
+            mPreviewOrientation = mJpegOrientation;
+        }
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java
index e48ce93..9204de3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java
@@ -19,31 +19,20 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.ImageFormat;
-import android.graphics.Matrix;
 import android.hardware.Camera;
 import android.os.Bundle;
-import android.os.Handler;
 import android.util.Log;
 import android.view.SurfaceHolder;
-import android.view.SurfaceView;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout.LayoutParams;
+import android.widget.ImageButton;
 import android.widget.TextView;
 
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestResult;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
 import java.util.TreeSet;
 
 /**
@@ -88,8 +77,8 @@
         Camera.ACTION_NEW_VIDEO
     };
 
-    private Button mPassButton;
-    private Button mFailButton;
+    private ImageButton mPassButton;
+    private ImageButton mFailButton;
     private Button mStartTestButton;
 
     private int mState = STATE_OFF;
@@ -212,8 +201,8 @@
         setPassFailButtonClickListeners();
         setInfoResources(R.string.camera_intents, R.string.ci_info, -1);
 
-        mPassButton         = (Button) findViewById(R.id.pass_button);
-        mFailButton         = (Button) findViewById(R.id.fail_button);
+        mPassButton         = (ImageButton) findViewById(R.id.pass_button);
+        mFailButton         = (ImageButton) findViewById(R.id.fail_button);
         mStartTestButton  = (Button) findViewById(R.id.start_test_button);
         mStartTestButton.setOnClickListener(this);
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java
index b970e40..273d78a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java
@@ -27,6 +27,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout.LayoutParams;
 import android.widget.TextView;
@@ -55,8 +56,8 @@
     private static final int NUM_ORIENTATIONS = 4;
     private static final String STAGE_INDEX_EXTRA = "stageIndex";
 
-    private Button mPassButton;
-    private Button mFailButton;
+    private ImageButton mPassButton;
+    private ImageButton mFailButton;
     private Button mTakePictureButton;
 
     private SurfaceView mCameraView;
@@ -85,8 +86,8 @@
         setInfoResources(R.string.camera_orientation, R.string.co_info, -1);
         mNumCameras = Camera.getNumberOfCameras();
 
-        mPassButton         = (Button) findViewById(R.id.pass_button);
-        mFailButton         = (Button) findViewById(R.id.fail_button);
+        mPassButton         = (ImageButton) findViewById(R.id.pass_button);
+        mFailButton         = (ImageButton) findViewById(R.id.fail_button);
         mTakePictureButton  = (Button) findViewById(R.id.take_picture_button);
         mFormatView         = (ImageView) findViewById(R.id.format_view);
         mCameraView         = (SurfaceView) findViewById(R.id.camera_view);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
index b010f79..0a0e830 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
@@ -35,6 +35,7 @@
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
+import android.widget.ImageButton;
 import android.widget.Spinner;
 import android.widget.TextView;
 import android.widget.VideoView;
@@ -69,6 +70,7 @@
     private int mPreviewTexWidth;
     private int mPreviewTexHeight;
     private int mPreviewRotation;
+    private int mVideoRotation;
 
     private VideoView mPlaybackView;
 
@@ -89,8 +91,8 @@
     private boolean isRecording = false;
     private boolean isPlayingBack = false;
     private Button captureButton;
-    private Button mPassButton;
-    private Button mFailButton;
+    private ImageButton mPassButton;
+    private ImageButton mFailButton;
 
     private TextView mStatusLabel;
 
@@ -161,7 +163,10 @@
         // Step 5: set preview output
         // This is not necessary since preview has been taken care of
 
-        // Step 6: prepare configured MediaRecorder
+        // Step 6: set orientation hint
+        mMediaRecorder.setOrientationHint(mVideoRotation);
+
+        // Step 7: prepare configured MediaRecorder
         try {
             mMediaRecorder.prepare();
         } catch (IOException e) {
@@ -204,8 +209,8 @@
         mPlaybackView.setOnCompletionListener(mPlaybackViewListener);
 
         captureButton = (Button) findViewById(R.id.record_button);
-        mPassButton = (Button) findViewById(R.id.pass_button);
-        mFailButton = (Button) findViewById(R.id.fail_button);
+        mPassButton = (ImageButton) findViewById(R.id.pass_button);
+        mFailButton = (ImageButton) findViewById(R.id.fail_button);
         mPassButton.setEnabled(false);
         mFailButton.setEnabled(true);
 
@@ -449,7 +454,8 @@
                 CamcorderProfile.QUALITY_CIF,
                 CamcorderProfile.QUALITY_480P,
                 CamcorderProfile.QUALITY_720P,
-                CamcorderProfile.QUALITY_1080P
+                CamcorderProfile.QUALITY_1080P,
+                CamcorderProfile.QUALITY_2160P
         };
 
         String[] nameArray = {
@@ -460,7 +466,8 @@
                 "CIF",
                 "480P",
                 "720P",
-                "1080P"
+                "1080P",
+                "2160P"
         };
 
         ArrayList<VideoSizeNamePair> availableSizes =
@@ -499,7 +506,8 @@
                 CamcorderProfile.QUALITY_CIF,
                 CamcorderProfile.QUALITY_480P,
                 CamcorderProfile.QUALITY_720P,
-                CamcorderProfile.QUALITY_1080P
+                CamcorderProfile.QUALITY_1080P,
+                CamcorderProfile.QUALITY_2160P
         };
 
         ArrayList<ResolutionQuality> qualityList = new ArrayList<ResolutionQuality>();
@@ -640,10 +648,11 @@
         }
 
         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
-            mPreviewRotation = (info.orientation + degrees) % 360;
-            mPreviewRotation = (360 - mPreviewRotation) % 360;  // compensate the mirror
+            mVideoRotation = (info.orientation + degrees) % 360;
+            mPreviewRotation = (360 - mVideoRotation) % 360;  // compensate the mirror
         } else {  // back-facing
-            mPreviewRotation = (info.orientation - degrees + 360) % 360;
+            mVideoRotation = (info.orientation - degrees + 360) % 360;
+            mPreviewRotation = mVideoRotation;
         }
         if (mPreviewRotation != 0 && mPreviewRotation != 180) {
             Log.w(TAG,
@@ -731,10 +740,7 @@
                     public void onClick(DialogInterface dialog, int which) {
                         switch (which) {
                             case DialogInterface.BUTTON_POSITIVE:
-                                PassFailButtons.setTestResultAndFinish(CameraVideoActivity.this,
-                                        CameraVideoActivity.this.getTestId(),
-                                        CameraVideoActivity.this.getTestDetails(),
-                                        /* passed */false);
+                                setTestResultAndFinish(/* passed */false);
                                 break;
                             case DialogInterface.BUTTON_NEGATIVE:
                                 break;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 581121e..74a5317 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -169,6 +169,10 @@
     };
 
     public static final Feature[] ALL_JELLY_BEAN_FEATURES = {
+            // Required features in prior releases that became optional
+            new Feature(PackageManager.FEATURE_FAKETOUCH, false),
+
+            //new feature in JB
             new Feature(PackageManager.FEATURE_TELEVISION, false),
     };
 
@@ -190,6 +194,37 @@
 
     public static final Feature[] ALL_KITKAT_WATCH_FEATURES = {
             new Feature(PackageManager.FEATURE_SENSOR_HEART_RATE, false),
+            new Feature(PackageManager.FEATURE_BACKUP, false),
+            new Feature(PackageManager.FEATURE_PRINTING, false),
+            new Feature(PackageManager.FEATURE_WATCH, false),
+            new Feature(PackageManager.FEATURE_WEBVIEW, false),
+            new Feature(PackageManager.FEATURE_CAMERA_EXTERNAL, false),
+    };
+
+    public static final Feature[] ALL_LOLLIPOP_FEATURES = {
+            // New features in L
+            new Feature(PackageManager.FEATURE_AUDIO_OUTPUT, false),
+            new Feature(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING, false),
+            new Feature(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR, false),
+            new Feature(PackageManager.FEATURE_CAMERA_CAPABILITY_RAW, false),
+            new Feature(PackageManager.FEATURE_CAMERA_LEVEL_FULL, false),
+            new Feature(PackageManager.FEATURE_CONNECTION_SERVICE, false),
+            new Feature(PackageManager.FEATURE_GAMEPAD, false),
+            new Feature(PackageManager.FEATURE_LEANBACK, false),
+            new Feature(PackageManager.FEATURE_LIVE_TV, false),
+            new Feature(PackageManager.FEATURE_MANAGED_USERS, false),
+            new Feature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK, false),
+            new Feature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, false),
+            new Feature(PackageManager.FEATURE_SENSOR_AMBIENT_TEMPERATURE, false),
+            new Feature(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG, false),
+            new Feature(PackageManager.FEATURE_SENSOR_RELATIVE_HUMIDITY, false),
+            new Feature(PackageManager.FEATURE_VERIFIED_BOOT, false),
+
+            // New hidden features in L
+            new Feature("android.hardware.ethernet", false),
+            new Feature("android.hardware.hdmi.cec", false),
+            new Feature("android.software.leanback_only", false),
+            new Feature("android.software.voice_recognizers", false),
     };
 
     @Override
@@ -222,6 +257,9 @@
 
         // add features from latest to last so that the latest requirements are put in the set first
         int apiVersion = Build.VERSION.SDK_INT;
+        if (apiVersion >= Build.VERSION_CODES.LOLLIPOP) {
+            Collections.addAll(features, ALL_LOLLIPOP_FEATURES);
+        }
         if (apiVersion >= Build.VERSION_CODES.KITKAT_WATCH) {
             Collections.addAll(features, ALL_KITKAT_WATCH_FEATURES);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
new file mode 100644
index 0000000..2a94ace
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
@@ -0,0 +1,184 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.android.cts.verifier.R;
+
+/**
+ *  This activity runs the following tests:
+ *     - Ask the tester to unplug the phone, and verify that jobs with charging constraints will
+ *      not run.
+ *     - Ask the tester to ensure the phone is plugged in, and verify that jobs with charging
+ *      constraints are run.
+ */
+@TargetApi(21)
+public class ChargingConstraintTestActivity extends ConstraintTestActivity {
+
+    private static final int ON_CHARGING_JOB_ID =
+            ChargingConstraintTestActivity.class.hashCode() + 0;
+    private static final int OFF_CHARGING_JOB_ID =
+            ChargingConstraintTestActivity.class.hashCode() + 1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set up the UI.
+        setContentView(R.layout.js_charging);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.js_charging_test, R.string.js_charging_instructions, -1);
+        mStartButton = (Button) findViewById(R.id.js_charging_start_test_button);
+
+        mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+        // Register receiver for connected/disconnected power events.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
+        intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+
+        registerReceiver(mChargingChangedReceiver, intentFilter);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mChargingChangedReceiver);
+    }
+
+    @Override
+    public void startTestImpl() {
+        new TestDeviceUnpluggedConstraint().execute();
+    }
+
+    private BroadcastReceiver mChargingChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
+                mDeviceUnpluggedTestPassed = false;
+                mStartButton.setEnabled(true);
+            } else if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
+                mStartButton.setEnabled(false);
+                if (mDeviceUnpluggedTestPassed) {
+                    continueTest();
+                }
+            }
+        }
+    };
+
+    /** Simple state boolean we use to determine whether to continue with the second test. */
+    private boolean mDeviceUnpluggedTestPassed = false;
+
+    /**
+     * After the first test has passed, and preconditions are met, this will kick off the second
+     * test.
+     * See {@link #startTest(android.view.View)}.
+     */
+    private void continueTest() {
+        new TestDevicePluggedInConstraint().execute();
+    }
+
+    /**
+     * Test blocks and can't be run on the main thread.
+     */
+    private void testChargingConstraintFails_notCharging() {
+        mTestEnvironment.setUp();
+
+        mTestEnvironment.setExpectedExecutions(0);
+        JobInfo runOnCharge = new JobInfo.Builder(OFF_CHARGING_JOB_ID, mMockComponent)
+                .setRequiresCharging(true)
+                .build();
+        mJobScheduler.schedule(runOnCharge);
+
+        // Send intent to kick off any jobs. This will be a no-op as the device is not plugged in;
+        // the JobScheduler tracks charging state independently.
+        sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitTimeout();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        mDeviceUnpluggedTestPassed = testPassed;
+        runOnUiThread(new ChargingConstraintTestResultRunner(OFF_CHARGING_JOB_ID, testPassed));
+    }
+
+    /**
+     * Test blocks and can't be run on the main thread.
+     */
+    private void testChargingConstraintExecutes_onCharging() {
+        mTestEnvironment.setUp();
+
+        JobInfo delayConstraintAndUnexpiredDeadline =
+                new JobInfo.Builder(ON_CHARGING_JOB_ID, mMockComponent)
+                        .setRequiresCharging(true)
+                        .build();
+
+        mTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(delayConstraintAndUnexpiredDeadline);
+
+        // Force the JobScheduler to consider any jobs that have charging constraints.
+        sendBroadcast(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitExecution();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        runOnUiThread(new ChargingConstraintTestResultRunner(ON_CHARGING_JOB_ID, testPassed));
+    }
+
+    /** Run test for when the <bold>device is not connected to power.</bold>. */
+    private class TestDeviceUnpluggedConstraint extends AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testChargingConstraintFails_notCharging();
+
+            // Do not call notifyTestCompleted here, as we're still waiting for the user to put
+            // the device back on charge to continue with TestDevicePluggedInConstraint.
+            return null;
+        }
+    }
+
+    /** Run test for when the <bold>device is connected to power.</bold> */
+    private class TestDevicePluggedInConstraint extends AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testChargingConstraintExecutes_onCharging();
+
+            notifyTestCompleted();
+            return null;
+        }
+    }
+
+    private class ChargingConstraintTestResultRunner extends TestResultRunner {
+        ChargingConstraintTestResultRunner(int jobId, boolean testPassed) {
+            super(jobId, testPassed);
+        }
+
+        @Override
+        public void run() {
+            ImageView view;
+            if (mJobId == OFF_CHARGING_JOB_ID) {
+                view = (ImageView) findViewById(R.id.charging_off_test_image);
+            } else if (mJobId == ON_CHARGING_JOB_ID) {
+                view = (ImageView) findViewById(R.id.charging_on_test_image);
+            } else {
+                noteInvalidTest();
+                return;
+            }
+            view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
new file mode 100644
index 0000000..e97539d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
@@ -0,0 +1,184 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.android.cts.verifier.R;
+
+/**
+ * The majority of the connectivity constraints are done in the device-side test app
+ * android.jobscheduler.cts.deviceside. However a manual tester is required to completely turn off
+ * connectivity on the device in order to verify that jobs with connectivity constraints will not
+ * run in the absence of an internet connection.
+ */
+@TargetApi(21)
+public class ConnectivityConstraintTestActivity extends ConstraintTestActivity {
+    private static final String TAG = "ConnectivityConstraintTestActivity";
+    private static final int ANY_CONNECTIVITY_JOB_ID =
+            ConnectivityConstraintTestActivity.class.hashCode() + 0;
+    private static final int UNMETERED_CONNECTIVITY_JOB_ID =
+            ConnectivityConstraintTestActivity.class.hashCode() + 1;
+    private static final int NO_CONNECTIVITY_JOB_ID =
+            ConnectivityConstraintTestActivity.class.hashCode() + 2;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set up the UI.
+        setContentView(R.layout.js_connectivity);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.js_connectivity_test, R.string.js_connectivity_instructions, -1);
+        mStartButton = (Button) findViewById(R.id.js_connectivity_start_test_button);
+
+        // Disable test start if there is data connectivity.
+        mStartButton.setEnabled(isDataUnavailable());
+        // Register receiver to listen for connectivity changes.
+        IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+        registerReceiver(mConnectivityChangedReceiver, intentFilter);
+
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mConnectivityChangedReceiver);
+    }
+
+    @Override
+    protected void startTestImpl() {
+        new TestConnectivityConstraint().execute();
+    }
+
+    /** Ensure that there's no connectivity before we allow the test to start. */
+    BroadcastReceiver mConnectivityChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.d(TAG, "received: " + intent);
+            String extras = "";
+            for (String name : intent.getExtras().keySet()) {
+                extras += " |" + name + " " + intent.getExtras().get(name) + "|";
+
+            }
+            Log.d(TAG, "extras: " + extras);
+            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+                // Only enable the test when we know there is no connectivity.
+                mStartButton.setEnabled(isDataUnavailable());
+            }
+        }
+    };
+
+    private void testUnmeteredConstraintFails_noConnectivity() {
+        testConnectivityConstraintFailsImpl(
+                JobInfo.NETWORK_TYPE_UNMETERED, UNMETERED_CONNECTIVITY_JOB_ID);
+    }
+
+    private void testAnyConnectivityConstraintFails_noConnectivity() {
+        testConnectivityConstraintFailsImpl(JobInfo.NETWORK_TYPE_ANY, ANY_CONNECTIVITY_JOB_ID);
+    }
+
+    private void testNoConnectivityConstraintExecutes_noConnectivity() {
+        JobInfo testJob = new JobInfo.Builder(NO_CONNECTIVITY_JOB_ID, mMockComponent)
+                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
+                .setOverrideDeadline(100000L)  // Will not expire.
+                .build();
+
+        mTestEnvironment.setUp();
+        mTestEnvironment.setExpectedExecutions(1);
+
+        mJobScheduler.schedule(testJob);
+
+        // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
+        sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitExecution();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        runOnUiThread(
+                new ConnectivityConstraintTestResultRunner(NO_CONNECTIVITY_JOB_ID, testPassed));
+    }
+
+    private void testConnectivityConstraintFailsImpl(int requiredNetworkType, int jobId) {
+        // Use arguments provided to construct job with required connectivity constraint.
+        JobInfo testJob = new JobInfo.Builder(jobId, mMockComponent)
+                .setRequiredNetworkType(requiredNetworkType)
+                .build();
+
+        mTestEnvironment.setUp();
+        mTestEnvironment.setExpectedExecutions(0);
+
+        mJobScheduler.schedule(testJob);
+
+        // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
+        sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitTimeout();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        runOnUiThread(
+                new ConnectivityConstraintTestResultRunner(jobId, testPassed));
+    }
+
+    /** Query the active network connection and return if there is no data connection. */
+    private boolean isDataUnavailable() {
+        final ConnectivityManager cm =
+                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+        final NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+
+        return (activeNetwork == null) ||
+                !activeNetwork.isConnectedOrConnecting();
+    }
+
+    private class TestConnectivityConstraint extends AsyncTask<Void, Void, Void> {
+
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testUnmeteredConstraintFails_noConnectivity();
+            testAnyConnectivityConstraintFails_noConnectivity();
+            testNoConnectivityConstraintExecutes_noConnectivity();
+
+            notifyTestCompleted();
+            return null;
+        }
+    }
+
+    private class ConnectivityConstraintTestResultRunner extends TestResultRunner {
+        ConnectivityConstraintTestResultRunner(int jobId, boolean testPassed) {
+            super(jobId, testPassed);
+        }
+
+        @Override
+        public void run() {
+            ImageView view;
+            if (mJobId == ANY_CONNECTIVITY_JOB_ID) {
+                view = (ImageView) findViewById(R.id.connectivity_off_test_any_connectivity_image);
+            } else if (mJobId == UNMETERED_CONNECTIVITY_JOB_ID) {
+                view = (ImageView) findViewById(R.id.connectivity_off_test_unmetered_image);
+            } else if (mJobId == NO_CONNECTIVITY_JOB_ID) {
+                view = (ImageView) findViewById(R.id.connectivity_off_test_no_connectivity_image);
+            } else {
+                noteInvalidTest();
+                return;
+            }
+            view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+        }
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
new file mode 100644
index 0000000..da0862a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
@@ -0,0 +1,115 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@TargetApi(21)
+public abstract class ConstraintTestActivity extends PassFailButtons.Activity {
+    /**
+     * Intent we use to force the job scheduler to consider any ready jobs that otherwise it may
+     * have decided to be lazy about.
+     */
+    protected static final Intent EXPEDITE_STABLE_CHARGING =
+            new Intent("com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE");
+
+    protected ComponentName mMockComponent;
+
+    protected MockJobService.TestEnvironment mTestEnvironment;
+    protected JobScheduler mJobScheduler;
+
+    /** Avoid cases where user might press "start test" more than once. */
+    private boolean mTestInProgress;
+    /**
+     * Starts the test - set up by subclass, which also controls the logic for how/when the test
+     * can be started.
+     */
+    protected Button mStartButton;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        mMockComponent = new ComponentName(this, MockJobService.class);
+        mTestEnvironment = MockJobService.TestEnvironment.getTestEnvironment();
+    }
+
+    /** OnClickListener for the "Start Test" ({@link #mStartButton}) button */
+    public final void startTest(View v) {
+        if (mTestInProgress) {
+            Toast toast =
+                    Toast.makeText(
+                            ConstraintTestActivity.this,
+                            "Test already in progress",
+                            Toast.LENGTH_SHORT);
+            toast.show();
+            return;
+        } else {
+            mTestInProgress = true;
+            startTestImpl();
+        }
+    }
+
+    /** Called by subclasses to allow the user to rerun the test if necessary. */
+    protected final void notifyTestCompleted() {
+        mTestInProgress = false;
+    }
+
+    /** Implemented by subclasses to determine logic for running the test. */
+    protected abstract void startTestImpl();
+
+    /**
+     * Broadcast the provided intent, and register a receiver to notify us after the broadcast has
+     * been processed.
+     * This function will block until the broadcast comes back, and <bold>cannot</bold> be called
+     * on the main thread.
+     * @return True if we received the callback, false if not.
+     */
+    protected boolean sendBroadcastAndBlockForResult(Intent intent) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+            }
+        }, null, -1, null, null);
+        try {
+            return latch.await(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+
+    /** Extended by test activities to report results of a test. */
+    protected abstract class TestResultRunner implements Runnable {
+        final int mJobId;
+        final boolean mTestPassed;
+
+        TestResultRunner(int jobId, boolean testPassed) {
+            mJobId = jobId;
+            mTestPassed = testPassed;
+        }
+        protected void noteInvalidTest() {
+            final Toast toast =
+                    Toast.makeText(
+                            ConstraintTestActivity.this,
+                            "Invalid result returned from test thread: job=" + mJobId + ", res="
+                                    + mTestPassed,
+                            Toast.LENGTH_SHORT);
+            toast.show();
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
new file mode 100644
index 0000000..a8bd993
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.jobscheduler;
+
+import com.android.cts.verifier.R;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.ImageView;
+
+/**
+ *  Idle constraints:
+ *      The framework doesn't support turning idle mode off. Use the manual tester to ensure that
+ *      the device is not in idle mode (by turning the screen off and then back on) before running
+ *      the tests.
+ */
+@TargetApi(21)
+public class IdleConstraintTestActivity extends ConstraintTestActivity {
+    private static final String TAG = "IdleModeTestActivity";
+    /**
+     * It takes >1hr for idle mode to be triggered. We'll use this secret broadcast to force the
+     * scheduler into idle. It's not a protected broadcast so that's alright.
+     */
+    private static final String ACTION_EXPEDITE_IDLE_MODE =
+            "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
+
+    /**
+     * Id for the job that we schedule when the device is not in idle mode. This job is expected
+     * to not execute. Executing means that the verifier test should fail.
+     */
+    private static final int IDLE_OFF_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 0;
+    /**
+     * Id for the job that we schedule when the device *is* in idle mode. This job is expected to
+     * execute. Not executing means that the verifier test should fail.
+     */
+    private static final int IDLE_ON_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 1;
+
+    /**
+     * Listens for idle mode off/on events, namely {@link #ACTION_EXPEDITE_IDLE_MODE} and
+     * {@link Intent#ACTION_SCREEN_ON}.
+     * On ACTION_EXPEDITE_IDLE_MODE, we will disable the {@link #mStartButton}, and on
+     * ACTION_SCREEN_ON we enable it. This is to avoid the start button being clicked when the
+     * device is in idle mode.
+     */
+    private BroadcastReceiver mIdleChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
+                mStartButton.setEnabled(true);
+            } else if (ACTION_EXPEDITE_IDLE_MODE.equals(intent.getAction())) {
+                mStartButton.setEnabled(false);
+            } else {
+                Log.e(TAG, "Invalid broadcast received, was expecting SCREEN_ON");
+            }
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set up the UI.
+        setContentView(R.layout.js_idle);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.js_idle_test, R.string.js_idle_instructions, -1);
+        mStartButton = (Button) findViewById(R.id.js_idle_start_test_button);
+
+        // Register receiver for idle off/on events.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+        intentFilter.addAction(ACTION_EXPEDITE_IDLE_MODE);
+
+        registerReceiver(mIdleChangedReceiver, intentFilter);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mIdleChangedReceiver);
+    }
+
+    @Override
+    protected void startTestImpl() {
+        new TestIdleModeTask().execute();
+    }
+
+    /** Background task that will run the actual test. */
+    private class TestIdleModeTask extends AsyncTask<Void, Void, Void> {
+
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testIdleConstraintFails_notIdle();
+
+
+            // Send the {@link #ACTION_EXPEDITE_IDLE_MODE} broadcast as an ordered broadcast, this
+            // function will block until all receivers have processed the broadcast.
+            if (!sendBroadcastAndBlockForResult(new Intent(ACTION_EXPEDITE_IDLE_MODE))) {
+                // Fail the test if the broadcast wasn't processed.
+                runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, false));
+            }
+
+            testIdleConstraintExecutes_onIdle();
+
+            notifyTestCompleted();
+            return null;
+        }
+
+    }
+
+    /**
+     * The user has just pressed the "Start Test" button, so we know that the device can't be idle.
+     * Schedule a job with an idle constraint and verify that it doesn't execute.
+     */
+    private void testIdleConstraintFails_notIdle() {
+        mTestEnvironment.setUp();
+        mJobScheduler.cancelAll();
+
+        mTestEnvironment.setExpectedExecutions(0);
+
+        mJobScheduler.schedule(
+                new JobInfo.Builder(IDLE_OFF_JOB_ID, mMockComponent)
+                        .setRequiresDeviceIdle(true)
+                        .build());
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitTimeout();
+        } catch (InterruptedException e) {
+            // We'll just indicate that it failed, not why.
+            testPassed = false;
+        }
+        runOnUiThread(new IdleTestResultRunner(IDLE_OFF_JOB_ID, testPassed));
+    }
+
+    private void testIdleConstraintExecutes_onIdle() {
+        mTestEnvironment.setUp();
+        mJobScheduler.cancelAll();
+
+        mTestEnvironment.setExpectedExecutions(1);
+
+        mJobScheduler.schedule(
+                new JobInfo.Builder(IDLE_ON_JOB_ID, mMockComponent)
+                .setRequiresDeviceIdle(true)
+                .build());
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitExecution();
+        } catch (InterruptedException e) {
+            // We'll just indicate that it failed, not why.
+            testPassed = false;
+        }
+        runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, testPassed));
+    }
+
+    /**
+     * Runnable to update the UI with the outcome of the test. This class only runs two tests, so
+     * the argument passed into the constructor will indicate which of the tests we are reporting
+     * for.
+     */
+    protected class IdleTestResultRunner extends TestResultRunner {
+
+        IdleTestResultRunner(int jobId, boolean testPassed) {
+            super(jobId, testPassed);
+        }
+
+        @Override
+        public void run() {
+            ImageView view;
+            if (mJobId == IDLE_OFF_JOB_ID) {
+                view = (ImageView) findViewById(R.id.idle_off_test_image);
+            } else if (mJobId == IDLE_ON_JOB_ID) {
+                view = (ImageView) findViewById(R.id.idle_on_test_image);
+            } else {
+                noteInvalidTest();
+                return;
+            }
+            view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java
new file mode 100644
index 0000000..9595a6a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this
+ * class is configured through the static
+ * {@link TestEnvironment}.
+ */
+@TargetApi(21)
+public class MockJobService extends JobService {
+    private static final String TAG = "MockJobService";
+
+    /** Wait this long before timing out the test. */
+    private static final long DEFAULT_TIMEOUT_MILLIS = 5000L; // 5 seconds.
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.e(TAG, "Created test service.");
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        Log.i(TAG, "Test job executing: " + params.getJobId());
+
+        TestEnvironment.getTestEnvironment().notifyExecution(params.getJobId());
+        return false;  // No work to do.
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        return false;
+    }
+
+    /**
+     * Configures the expected behaviour for each test. This object is shared across consecutive
+     * tests, so to clear state each test is responsible for calling
+     * {@link TestEnvironment#setUp()}.
+     */
+    public static final class TestEnvironment {
+
+        private static TestEnvironment kTestEnvironment;
+        public static final int INVALID_JOB_ID = -1;
+
+        private CountDownLatch mLatch;
+        private int mExecutedJobId;
+
+        public static TestEnvironment getTestEnvironment() {
+            if (kTestEnvironment == null) {
+                kTestEnvironment = new TestEnvironment();
+            }
+            return kTestEnvironment;
+        }
+
+        /**
+         * Block the test thread, waiting on the JobScheduler to execute some previously scheduled
+         * job on this service.
+         */
+        public boolean awaitExecution() throws InterruptedException {
+            final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+            return executed;
+        }
+
+        /**
+         * Block the test thread, expecting to timeout but still listening to ensure that no jobs
+         * land in the interim.
+         * @return True if the latch timed out waiting on an execution.
+         */
+        public boolean awaitTimeout() throws InterruptedException {
+            return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        }
+
+        private void notifyExecution(int jobId) {
+            Log.d(TAG, "Job executed:" + jobId);
+            mExecutedJobId = jobId;
+            mLatch.countDown();
+        }
+
+        public void setExpectedExecutions(int numExecutions) {
+            // For no executions expected, set count to 1 so we can still block for the timeout.
+            if (numExecutions == 0) {
+                mLatch = new CountDownLatch(1);
+            } else {
+                mLatch = new CountDownLatch(numExecutions);
+            }
+        }
+
+        /** Called in each testCase#setup */
+        public void setUp() {
+            mLatch = null;
+            mExecutedJobId = INVALID_JOB_ID;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
new file mode 100644
index 0000000..da823e8
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestListActivity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CTS verifier test for BYOD managed provisioning flow.
+ * This activity is responsible for starting the managed provisioning flow and verify the outcome of provisioning.
+ * It performs the following verifications:
+ *   Full disk encryption is enabled.
+ *   Profile owner is correctly installed.
+ *   Profile owner shows up in the Settings app.
+ *   Badged work apps show up in launcher.
+ * The first two verifications are performed automatically, by interacting with profile owner using
+ * cross-profile intents, while the last two are carried out manually by the user.
+ */
+public class ByodFlowTestActivity extends PassFailButtons.ListActivity {
+
+    private final String TAG = "ByodFlowTestActivity";
+    private static final int REQUEST_STATUS = 1;
+
+    private ComponentName mAdminReceiverComponent;
+
+    private TestAdapter mAdapter;
+    private View mStartProvisioningButton;
+    private List<TestItem> mTests = new ArrayList<TestItem>();
+
+    protected DevicePolicyManager mDevicePolicyManager;
+
+    private TestItem mProfileOwnerInstalled;
+    private TestItem mDiskEncryptionTest;
+    private TestItem mProfileVisibleTest;
+    private TestItem mDeviceAdminVisibleTest;
+    private TestItem mWorkAppVisibleTest;
+    private TestItem mCrossProfileIntentFiltersTest;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+        mDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+        disableComponent();
+
+        setContentView(R.layout.provisioning_byod);
+        setInfoResources(R.string.provisioning_byod, R.string.provisioning_byod_info, -1);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setResult(RESULT_CANCELED);
+
+        setupTests();
+
+        mAdapter = new TestAdapter(this);
+        setListAdapter(mAdapter);
+        mAdapter.addAll(mTests);
+
+        mStartProvisioningButton = findViewById(R.id.byod_start);
+        mStartProvisioningButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                startByodProvisioning();
+            }
+        });
+
+        // If we are started by managed provisioning (fresh managed provisioning after encryption
+        // reboot), redirect the user back to the main test list. This is because the test result
+        // is only saved by the parent TestListActivity, and if we did allow the user to proceed
+        // here, the test result would be lost when this activity finishes.
+        if (ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS.equals(getIntent().getAction())) {
+            startActivity(new Intent(this, TestListActivity.class));
+            // Calling super.finish() because we delete managed profile in our overridden of finish(),
+            // which is not what we want to do here.
+            super.finish();
+        } else {
+            queryProfileOwner(false);
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        // This is called when managed provisioning completes successfully without reboot.
+        super.onNewIntent(intent);
+        if (ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS.equals(intent.getAction())) {
+            handleStatusUpdate(intent);
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        // Called after queryProfileOwner()
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == REQUEST_STATUS && resultCode == RESULT_OK) {
+            handleStatusUpdate(data);
+        }
+    }
+
+    private void handleStatusUpdate(Intent data) {
+        boolean provisioned = data.getBooleanExtra(ByodHelperActivity.EXTRA_PROVISIONED, false);
+        setTestResult(mProfileOwnerInstalled, provisioned ? TestResult.Passed : TestResult.Failed);
+    }
+
+    @Override
+    public void finish() {
+        // Pass and fail buttons are known to call finish() when clicked, and this is when we want to
+        // clean up the provisioned profile.
+        requestDeleteProfileOwner();
+        super.finish();
+    }
+
+    private void setupTests() {
+        mProfileOwnerInstalled = new TestItem(this, R.string.provisioning_byod_profileowner) {
+            @Override
+            public void performTest(ByodFlowTestActivity activity) {
+                queryProfileOwner(true);
+            }
+        };
+
+        mDiskEncryptionTest = new TestItem(this, R.string.provisioning_byod_diskencryption) {
+            @Override
+            public TestResult getPassFailState() {
+                return isDeviceEncrypted() ? TestResult.Passed : TestResult.Failed;
+            }
+        };
+
+        mProfileVisibleTest = new TestItem(this, R.string.provisioning_byod_profile_visible,
+                R.string.provisioning_byod_profile_visible_instruction,
+                new Intent(Settings.ACTION_SETTINGS));
+
+        mDeviceAdminVisibleTest = new TestItem(this, R.string.provisioning_byod_admin_visible,
+                R.string.provisioning_byod_admin_visible_instruction,
+                new Intent(Settings.ACTION_SECURITY_SETTINGS));
+
+        mWorkAppVisibleTest = new TestItem(this, R.string.provisioning_byod_workapps_visible,
+                R.string.provisioning_byod_workapps_visible_instruction,
+                new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
+
+        Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+        Intent chooser = Intent.createChooser(intent, getResources().getString(R.string.provisioning_cross_profile_chooser));
+        mCrossProfileIntentFiltersTest = new TestItem(this,
+                R.string.provisioning_byod_cross_profile,
+                R.string.provisioning_byod_cross_profile_instruction,
+                chooser);
+
+        mTests.add(mDiskEncryptionTest);
+        mTests.add(mProfileOwnerInstalled);
+        mTests.add(mProfileVisibleTest);
+        mTests.add(mDeviceAdminVisibleTest);
+        mTests.add(mWorkAppVisibleTest);
+        mTests.add(mCrossProfileIntentFiltersTest);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        super.onListItemClick(l, v, position, id);
+        TestItem test = (TestItem) getListAdapter().getItem(position);
+        test.performTest(this);
+    }
+
+    private void showManualTestDialog(final TestItem test) {
+        AlertDialog dialog = new AlertDialog.Builder(this)
+                .setIcon(android.R.drawable.ic_dialog_info)
+                .setMessage(test.getManualTestInstruction())
+                .setNeutralButton(R.string.provisioning_byod_go, null)
+                .setPositiveButton(R.string.pass_button_text, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        setTestResult(test, TestResult.Passed);
+                    }
+                })
+                .setNegativeButton(R.string.fail_button_text, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        setTestResult(test, TestResult.Failed);
+                    }
+                })
+                .create();
+        dialog.show();
+
+        dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ByodFlowTestActivity.this.startActivity(test.getManualTestIntent());
+            }
+        });
+    }
+
+    private void setTestResult(TestItem test, TestResult result) {
+        test.setPassFailState(result);
+
+        boolean testSucceeds = true;
+        for(TestItem aTest : mTests) {
+            testSucceeds &= (aTest.getPassFailState() == TestResult.Passed);
+        }
+        getPassButton().setEnabled(testSucceeds);
+        mAdapter.notifyDataSetChanged();
+    }
+
+    private void startByodProvisioning() {
+        Intent sending = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
+        sending.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
+                mAdminReceiverComponent.getPackageName());
+        sending.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminReceiverComponent);
+
+        if (sending.resolveActivity(getPackageManager()) != null) {
+            // ManagedProvisioning must be started with startActivityForResult, but we don't
+            // care about the result, so passing 0 as a requestCode
+            startActivityForResult(sending, 0);
+        } else {
+            showToast(R.string.provisioning_byod_disabled);
+        }
+    }
+
+    private void queryProfileOwner(boolean showToast) {
+        try {
+            Intent intent = new Intent(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
+            startActivityForResult(intent, REQUEST_STATUS);
+        }
+        catch (ActivityNotFoundException e) {
+            Log.d(TAG, "queryProfileOwner: ActivityNotFoundException", e);
+            setTestResult(mProfileOwnerInstalled, TestResult.Failed);
+            if (showToast) {
+                showToast(R.string.provisioning_byod_no_activity);
+            }
+        }
+    }
+
+    private void requestDeleteProfileOwner() {
+        try {
+            Intent intent = new Intent(ByodHelperActivity.ACTION_REMOVE_PROFILE_OWNER);
+            startActivity(intent);
+            showToast(R.string.provisioning_byod_delete_profile);
+        }
+        catch (ActivityNotFoundException e) {
+            Log.d(TAG, "requestDeleteProfileOwner: ActivityNotFoundException", e);
+        }
+    }
+
+    private void disableComponent() {
+        // Disable app components in the current profile, so only the counterpart in the other profile
+        // can respond (via cross-profile intent filter)
+        getPackageManager().setComponentEnabledSetting(new ComponentName(
+                this, ByodHelperActivity.class),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP);
+    }
+
+    private boolean isDeviceEncrypted() {
+        return mDevicePolicyManager.getStorageEncryptionStatus()
+                == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
+    }
+
+    private void showToast(int messageId) {
+        String message = getString(messageId);
+        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
+    }
+
+    enum TestResult {
+        Unknown, Failed, Passed
+    }
+
+    static class TestItem {
+
+        private String mDisplayName;
+        private TestResult mPassed;
+        private boolean mManualTest;
+        private String mManualInstruction;
+        private Intent mManualIntent;
+
+        public TestItem(Context context, int nameResId) {
+            mDisplayName = context.getString(nameResId);
+            mPassed = TestResult.Unknown;
+            mManualTest = false;
+        }
+
+        public void performTest(ByodFlowTestActivity activity) {
+            if (isManualTest()) {
+                activity.showManualTestDialog(this);
+            }
+        }
+
+        public TestItem(Context context, int nameResId, int testInstructionResId, Intent testIntent) {
+            mDisplayName = context.getString(nameResId);
+            mPassed = TestResult.Unknown;
+            mManualTest = true;
+            mManualInstruction = context.getString(testInstructionResId);
+            mManualIntent = testIntent;
+        }
+
+        @Override
+        public String toString() {
+            return mDisplayName;
+        }
+
+        TestResult getPassFailState() {
+            return mPassed;
+        }
+
+        void setPassFailState(TestResult state) {
+            mPassed = state;
+        }
+
+        public boolean isManualTest() {
+            return mManualTest;
+        }
+
+        public String getManualTestInstruction() {
+            return mManualInstruction;
+        }
+
+        public Intent getManualTestIntent() {
+            return mManualIntent;
+        }
+    }
+
+    static class TestAdapter extends ArrayAdapter<TestItem> {
+
+        public TestAdapter(Context context) {
+            super(context, android.R.layout.simple_list_item_1);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView view = (TextView) super.getView(position, convertView, parent);
+
+            TestItem item = getItem(position);
+            int backgroundResource = 0;
+            int iconResource = 0;
+            if (item.getPassFailState() == TestResult.Passed) {
+                backgroundResource = R.drawable.test_pass_gradient;
+                iconResource = R.drawable.fs_good;
+            } else if (item.getPassFailState() == TestResult.Failed){
+                backgroundResource = R.drawable.test_fail_gradient;
+                iconResource = R.drawable.fs_error;
+            }
+            view.setBackgroundResource(backgroundResource);
+            view.setPadding(10, 0, 10, 0);
+            view.setCompoundDrawablePadding(10);
+            view.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0);
+
+            return view;
+        }
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
new file mode 100644
index 0000000..5dac4bd
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.managedprovisioning.ByodFlowTestActivity.TestResult;
+
+/**
+ * A helper activity from the managed profile side that responds to requests from CTS verifier in
+ * primary user. Profile owner APIs are accessible inside this activity (given this activity is
+ * started within the work profile). Its current functionalities include making sure the profile
+ * owner is setup correctly, and removing the work profile upon request.
+ *
+ * Note: We have to use a dummy activity because cross-profile intents only work for activities.
+ */
+public class ByodHelperActivity extends Activity {
+    static final String TAG = "ByodHelperActivity";
+
+    // Primary -> managed intent: query if the profile owner has been set up.
+    public static final String ACTION_QUERY_PROFILE_OWNER = "com.android.cts.verifier.managedprovisioning.BYOD_QUERY";
+    // Managed -> primary intent: update profile owner test status in primary's CtsVerifer
+    public static final String ACTION_PROFILE_OWNER_STATUS = "com.android.cts.verifier.managedprovisioning.BYOD_STATUS";
+    // Primary -> managed intent: request to delete the current profile
+    public static final String ACTION_REMOVE_PROFILE_OWNER = "com.android.cts.verifier.managedprovisioning.BYOD_REMOVE";
+    // Managed -> managed intent: provisioning completed successfully
+    public static final String ACTION_PROFILE_PROVISIONED = "com.android.cts.verifier.managedprovisioning.BYOD_PROVISIONED";
+
+    public static final String EXTRA_PROVISIONED = "extra_provisioned";
+
+    private ComponentName mAdminReceiverComponent;
+
+    private DevicePolicyManager mDevicePolicyManager;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+        mDevicePolicyManager = (DevicePolicyManager) getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        String action = getIntent().getAction();
+        Log.d(TAG, "ByodHelperActivity.onCreate: " + action);
+
+        // we are explicitly started by {@link DeviceAdminTestReceiver} after a successful provisioning.
+        if (action.equals(ACTION_PROFILE_PROVISIONED)) {
+            // Jump back to CTS verifier with result.
+            Intent response = new Intent(ACTION_PROFILE_OWNER_STATUS);
+            response.putExtra(EXTRA_PROVISIONED, isProfileOwner());
+            startActivityInPrimary(response);
+            // Queried by CtsVerifier in the primary side using startActivityForResult.
+        } else if (action.equals(ACTION_QUERY_PROFILE_OWNER)) {
+            Intent response = new Intent();
+            response.putExtra(EXTRA_PROVISIONED, isProfileOwner());
+            setResult(RESULT_OK, response);
+            // Request to delete work profile.
+        } else if (action.equals(ACTION_REMOVE_PROFILE_OWNER)) {
+            if (isProfileOwner()) {
+                mDevicePolicyManager.wipeData(0);
+                showToast(R.string.provisioning_byod_profile_deleted);
+            }
+        }
+        // This activity has no UI and is only used to respond to CtsVerifier in the primary side.
+        finish();
+    }
+
+    private boolean isProfileOwner() {
+        return mDevicePolicyManager.isAdminActive(mAdminReceiverComponent) &&
+                mDevicePolicyManager.isProfileOwnerApp(mAdminReceiverComponent.getPackageName());
+    }
+
+    private void startActivityInPrimary(Intent intent) {
+        // Disable app components in the current profile, so only the counterpart in the other
+        // profile can respond (via cross-profile intent filter)
+        getPackageManager().setComponentEnabledSetting(new ComponentName(
+                this, ByodFlowTestActivity.class),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP);
+        startActivity(intent);
+    }
+
+    private void showToast(int messageId) {
+        String message = getString(messageId);
+        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
new file mode 100644
index 0000000..6c38e12
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+//package com.android.cts.verifier.managedprovisioning;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserManager;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Test activity for cross profile intents.
+ */
+public class CrossProfileTestActivity extends Activity {
+    // Intent for app in both profiles
+    public static final String ACTION_CROSS_PROFILE = "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.provisioning_cross_profile);
+        TextView textView = (TextView) findViewById(R.id.text);
+
+        // Check if we are running in the work or personal side, by testing if currently we are the
+        // profile owner or not.
+        textView.setText(isProfileOwner() ? R.string.provisioning_byod_cross_profile_app_work
+                : R.string.provisioning_byod_cross_profile_app_personal);
+
+        findViewById(R.id.button_finish).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                CrossProfileTestActivity.this.finish();
+            }
+        });
+    }
+
+    private boolean isProfileOwner() {
+        ComponentName adminReceiver = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+        DevicePolicyManager dpm = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+        return dpm.isAdminActive(adminReceiver) && dpm.isProfileOwnerApp(adminReceiver.getPackageName());
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
new file mode 100644
index 0000000..8dccac3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.cts.verifier.managedprovisioning.ByodHelperActivity;
+
+/**
+ * Profile owner receiver for BYOD flow test.
+ * Setup cross-profile intent filter after successful provisioning.
+ */
+public class DeviceAdminTestReceiver extends DeviceAdminReceiver {
+        private static final String TAG = "DeviceAdminTestReceiver";
+
+        @Override
+        public void onProfileProvisioningComplete(Context context, Intent intent) {
+            Log.d(TAG, "Provisioning complete intent received");
+            setupProfile(context);
+        }
+
+        private void setupProfile(Context context) {
+            DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+            dpm.setProfileEnabled(new ComponentName(context.getApplicationContext(), getClass()));
+
+            // Setup cross-profile intent filter to allow communications between the two versions of CtsVerifier
+            // Primary -> work direction
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
+            filter.addAction(ByodHelperActivity.ACTION_REMOVE_PROFILE_OWNER);
+            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+            dpm.addCrossProfileIntentFilter(getWho(context), filter,
+                    DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
+
+            // Work -> primary direction
+            filter = new IntentFilter();
+            filter.addAction(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
+            dpm.addCrossProfileIntentFilter(getWho(context), filter,
+                    DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
+
+            Intent intent = new Intent(context, ByodHelperActivity.class);
+            intent.setAction(ByodHelperActivity.ACTION_PROFILE_PROVISIONED);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            context.startActivity(intent);
+        }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerTestActivity.java
new file mode 100644
index 0000000..7cb3825
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerTestActivity.java
@@ -0,0 +1,93 @@
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.IntentDrivenTestActivity;
+import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
+import com.android.cts.verifier.IntentDrivenTestActivity.TestInfo;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestListAdapter.TestListItem;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Activity that lists all device owner provisioning tests.
+ */
+public class DeviceOwnerTestActivity extends PassFailButtons.TestListActivity {
+
+    private static final String ACTION_PROVISION_MANAGED_DEVICE
+        = "com.android.managedprovisioning.ACTION_PROVISION_MANAGED_DEVICE";
+    private static final Intent PROVISION_DEVICE_INTENT =
+            new Intent(ACTION_PROVISION_MANAGED_DEVICE);
+
+    private static final String DEVICE_OWNER_NEGATIVE_TEST = "DEVICE_OWNER_PROVISIONING_NEGATIVE";
+    private static final TestInfo DEVICE_OWNER_NEGATIVE_TEST_INFO = new TestInfo(
+                    DEVICE_OWNER_NEGATIVE_TEST,
+                    R.string.device_owner_negative_test,
+                    R.string.device_owner_negative_test_info,
+                    new ButtonInfo(
+                            R.string.start_device_owner_provisioning_button,
+                            PROVISION_DEVICE_INTENT));
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_list);
+        setInfoResources(R.string.device_owner_provisioning_tests,
+                R.string.device_owner_provisioning_tests_info, 0);
+        setPassFailButtonClickListeners();
+
+        final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
+        adapter.add(TestListItem.newCategory(this, R.string.device_owner_provisioning_category));
+
+        Intent startTestIntent = new Intent(this, IntentDrivenTestActivity.class)
+                    .putExtra(IntentDrivenTestActivity.EXTRA_ID,
+                            DEVICE_OWNER_NEGATIVE_TEST_INFO.getTestId())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_TITLE,
+                            DEVICE_OWNER_NEGATIVE_TEST_INFO.getTitle())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_INFO,
+                            DEVICE_OWNER_NEGATIVE_TEST_INFO.getInfoText())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_BUTTONS,
+                            DEVICE_OWNER_NEGATIVE_TEST_INFO.getButtons());
+
+
+        adapter.add(TestListItem.newTest(this, DEVICE_OWNER_NEGATIVE_TEST_INFO.getTitle(),
+                DEVICE_OWNER_NEGATIVE_TEST_INFO.getTestId(), startTestIntent, null));
+
+        adapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                updatePassButton();
+            }
+        });
+
+        setTestListAdapter(adapter);
+    }
+
+    /**
+     * Enable Pass Button when the all tests passed.
+     */
+    private void updatePassButton() {
+        getPassButton().setEnabled(mAdapter.allTestsPassed());
+    }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java
index 40a12ae..644e637 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java
@@ -66,6 +66,22 @@
                 .setPositiveButton("OK", null)
                 .create();
     }
+
+    public static AlertDialog createChangeForegroundDialog(final Context context) {
+        return new AlertDialog.Builder(context)
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setTitle(R.string.nfc_hce_tap_reader_title)
+                .setMessage(context.getString(R.string.nfc_hce_change_favor_foreground))
+                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        Intent intent = new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS);
+                        context.startActivity(intent);
+                    }
+                })
+                .create();
+    }
+
     private NfcDialogs() {
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/AccessService.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/AccessService.java
index 969f621..51eb7ec 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/AccessService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/AccessService.java
@@ -7,9 +7,9 @@
             new ComponentName("com.android.cts.verifier",
             AccessService.class.getName());
 
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu(HceUtils.ACCESS_AID),
-        "80CA01F000"
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.ACCESS_AID, true),
+        HceUtils.buildCommandApdu("80CA01F000", true)
     };
 
     public static final String[] APDU_RESPOND_SEQUENCE = {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java
index bcd2b8d..8aa82b5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/BaseEmulatorActivity.java
@@ -1,10 +1,13 @@
 package com.android.cts.verifier.nfc.hce;
 
 import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.nfc.NfcAdapter;
@@ -19,7 +22,6 @@
 
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
-import com.android.cts.verifier.nfc.hce.PaymentService1;
 
 @TargetApi(19)
 public abstract class BaseEmulatorActivity extends PassFailButtons.Activity {
@@ -27,6 +29,7 @@
     NfcAdapter mAdapter;
     CardEmulation mCardEmulation;
     ProgressDialog mSetupDialog;
+    ComponentName mMakingDefault;
 
     final ArrayList<ComponentName> SERVICES = new ArrayList<ComponentName>(
             Arrays.asList(
@@ -36,7 +39,13 @@
             TransportService2.COMPONENT,
             AccessService.COMPONENT,
             ThroughputService.COMPONENT,
-            OffHostService.COMPONENT)
+            OffHostService.COMPONENT,
+            PaymentServiceDynamicAids.COMPONENT,
+            PrefixPaymentService1.COMPONENT,
+            PrefixPaymentService2.COMPONENT,
+            PrefixTransportService1.COMPONENT,
+            PrefixTransportService2.COMPONENT,
+            PrefixAccessService.COMPONENT)
     );
 
     @Override
@@ -73,6 +82,29 @@
         new SetupServicesTask().execute(components);
     }
 
+    final boolean makePaymentDefault(final ComponentName defaultComponent, int stringId) {
+        if (!mCardEmulation.isDefaultServiceForCategory(defaultComponent,
+                CardEmulation.CATEGORY_PAYMENT)) {
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setTitle("Note");
+            builder.setMessage(stringId);
+            mMakingDefault = defaultComponent;
+            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                Intent changeDefault = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
+                changeDefault.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_PAYMENT);
+                changeDefault.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, defaultComponent);
+                startActivityForResult(changeDefault, 0);
+                }
+            });
+            builder.show();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -127,5 +159,38 @@
                     CardEmulation.CATEGORY_PAYMENT);
             return true;
         }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode == Activity.RESULT_OK) {
+            // Verify it's default
+            if (!mCardEmulation.isDefaultServiceForCategory(mMakingDefault,
+                    CardEmulation.CATEGORY_PAYMENT)) {
+                // Popup dialog-box
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                builder.setTitle("Test failed.");
+                builder.setMessage("The service was not made the default service according " +
+                        "to CardEmulation.getDefaultServiceForCategory(), verify the make " +
+                        "default implementation is correct.");
+                builder.setPositiveButton("OK", null);
+                builder.show();
+                onPaymentDefaultResult(mMakingDefault, false);
+            } else {
+                onPaymentDefaultResult(mMakingDefault, true);
+            }
+        } else {
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setTitle("Test failed.");
+            builder.setMessage("You clicked no.");
+            builder.setPositiveButton("OK", null);
+            builder.show();
+            onPaymentDefaultResult(mMakingDefault, false);
+        }
+    }
+
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+
     };
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ChangeDefaultEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ChangeDefaultEmulatorActivity.java
index 0681f49..633a152 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ChangeDefaultEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ChangeDefaultEmulatorActivity.java
@@ -1,20 +1,16 @@
 package com.android.cts.verifier.nfc.hce;
 
 import android.annotation.TargetApi;
-import android.app.AlertDialog;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
-import android.nfc.cardemulation.CardEmulation;
 import android.os.Bundle;
 
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.nfc.NfcDialogs;
 
 @TargetApi(19)
-public class ChangeDefaultEmulatorActivity extends BaseEmulatorActivity implements OnClickListener {
+public class ChangeDefaultEmulatorActivity extends BaseEmulatorActivity {
     final static int STATE_IDLE = 0;
     final static int STATE_SERVICE1_SETTING_UP = 1;
     final static int STATE_SERVICE2_SETTING_UP = 2;
@@ -48,22 +44,14 @@
             setupServices(this, PaymentService1.COMPONENT, PaymentService2.COMPONENT);
             return;
         }
-        // Verify HCE service 2 is the default
-        if (!mCardEmulation.isDefaultServiceForCategory(
-                PaymentService2.COMPONENT, CardEmulation.CATEGORY_PAYMENT)) {
-            mState = STATE_MAKING_SERVICE2_DEFAULT;
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setTitle("Note");
-            builder.setMessage(R.string.nfc_hce_change_preinstalled_wallet);
-            builder.setPositiveButton("OK", this);
-            builder.show();
-        } else {
+        if (!makePaymentDefault(PaymentService2.COMPONENT,
+                R.string.nfc_hce_change_preinstalled_wallet)) {
+            // Service 2 is already default, make one default now
             mState = STATE_MAKING_SERVICE1_DEFAULT;
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setTitle("Note");
-            builder.setMessage(R.string.nfc_hce_change_default_help);
-            builder.setPositiveButton("OK", this);
-            builder.show();
+            makePaymentDefault(PaymentService1.COMPONENT, R.string.nfc_hce_change_default_help);
+        } else {
+            mState = STATE_MAKING_SERVICE2_DEFAULT;
+            // will get callback when 2 is made default
         }
     }
 
@@ -94,57 +82,17 @@
     }
 
     @Override
-    public void onClick(DialogInterface dialog, int which) {
-        if (mState == STATE_MAKING_SERVICE1_DEFAULT) {
-            Intent changeDefault = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
-            changeDefault.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_PAYMENT);
-            changeDefault.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, PaymentService1.COMPONENT);
-            startActivityForResult(changeDefault, 0);
-        } else if (mState == STATE_MAKING_SERVICE2_DEFAULT) {
-            Intent changeDefault = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
-            changeDefault.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_PAYMENT);
-            changeDefault.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, PaymentService2.COMPONENT);
-            startActivityForResult(changeDefault, 0);
-        }
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-        if (mState == STATE_MAKING_SERVICE1_DEFAULT) {
-            if (!mCardEmulation.isDefaultServiceForCategory(
-                    PaymentService1.COMPONENT, CardEmulation.CATEGORY_PAYMENT)) {
-                // Popup dialog-box, fail test
-                AlertDialog.Builder builder = new AlertDialog.Builder(this);
-                builder.setTitle("Test failed.");
-                builder.setMessage("PaymentService1 is not the default service according " +
-                        "to CardEmulation.getDefaultServiceForCategory(), verify the make " +
-                        "default implementation is correct.");
-                builder.setPositiveButton("OK", null);
-                builder.show();
-            } else {
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+        if (mState == STATE_MAKING_SERVICE2_DEFAULT) {
+            if (success) {
+                mState = STATE_MAKING_SERVICE1_DEFAULT;
+	            makePaymentDefault(PaymentService1.COMPONENT, R.string.nfc_hce_change_default_help);
+            }
+        } else if (mState == STATE_MAKING_SERVICE1_DEFAULT) {
+            if (success) {
                 mState = STATE_DEFAULT_CHANGED;
                 NfcDialogs.createHceTapReaderDialog(this, null).show();
             }
-        } else if (mState == STATE_MAKING_SERVICE2_DEFAULT) {
-            if (!mCardEmulation.isDefaultServiceForCategory(
-                    PaymentService2.COMPONENT, CardEmulation.CATEGORY_PAYMENT)) {
-                // Popup dialog-box, fail test
-                AlertDialog.Builder builder = new AlertDialog.Builder(this);
-                builder.setTitle("Test failed.");
-                builder.setMessage("PaymentService2 is not the default service according " +
-                        "to CardEmulation.getDefaultServiceForCategory(), verify the make " +
-                        "default implementation is correct.");
-                builder.setPositiveButton("OK", null);
-                builder.show();
-            } else {
-                mState = STATE_MAKING_SERVICE1_DEFAULT;
-                AlertDialog.Builder builder = new AlertDialog.Builder(this);
-                builder.setTitle("Note");
-                builder.setMessage(R.string.nfc_hce_change_default_help);
-                builder.setPositiveButton("OK", this);
-                builder.show();
-            }
         }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/CommandApdu.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/CommandApdu.java
new file mode 100644
index 0000000..3039efd
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/CommandApdu.java
@@ -0,0 +1,49 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class CommandApdu implements Parcelable {
+    private String mApdu;
+    private boolean mReachable;
+
+    public CommandApdu(String apdu, boolean reachable) {
+        mApdu = apdu;
+        mReachable = reachable;
+    }
+
+    public boolean isReachable() {
+        return mReachable;
+    }
+
+    public String getApdu() {
+        return mApdu;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<CommandApdu> CREATOR =
+            new Parcelable.Creator<CommandApdu>() {
+        @Override
+        public CommandApdu createFromParcel(Parcel source) {
+            String apdu = source.readString();
+            boolean reachable = source.readInt() != 0 ? true : false;
+            return new CommandApdu(apdu, reachable);
+        }
+
+        @Override
+        public CommandApdu[] newArray(int size) {
+            return new CommandApdu[size];
+        }
+    };
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mApdu);
+        dest.writeInt(mReachable ? 1 : 0);
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ConflictingNonPaymentPrefixEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ConflictingNonPaymentPrefixEmulatorActivity.java
new file mode 100644
index 0000000..3b0313a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ConflictingNonPaymentPrefixEmulatorActivity.java
@@ -0,0 +1,54 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.NfcDialogs;
+
+import java.util.ArrayList;
+
+public class ConflictingNonPaymentPrefixEmulatorActivity extends BaseEmulatorActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_text);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setupServices(this, PrefixTransportService1.COMPONENT, PrefixTransportService2.COMPONENT);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    void onServicesSetup(boolean result) {
+        // Do dynamic AID registration
+        ArrayList<String> service_aids = new ArrayList<String>();
+        service_aids.add(HceUtils.TRANSPORT_PREFIX_AID + "*");
+        mCardEmulation.registerAidsForService(PrefixTransportService1.COMPONENT, CardEmulation.CATEGORY_OTHER, service_aids);
+        mCardEmulation.registerAidsForService(PrefixTransportService2.COMPONENT, CardEmulation.CATEGORY_OTHER, service_aids);
+        NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_other_conflicting_prefix_aids_help)).show();
+    }
+
+    public static Intent buildReaderIntent(Context context) {
+        Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS, PrefixTransportService2.APDU_COMMAND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES, PrefixTransportService2.APDU_RESPOND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_LABEL,
+                context.getString(R.string.nfc_hce_other_conflicting_prefix_aids_reader));
+        return readerIntent;
+    }
+
+    @Override
+    void onApduSequenceComplete(ComponentName component, long duration) {
+        if (component.equals(PrefixTransportService2.COMPONENT)) {
+            getPassButton().setEnabled(true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DefaultRouteEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DefaultRouteEmulatorActivity.java
index 2de99e7..fbf07e7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DefaultRouteEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DefaultRouteEmulatorActivity.java
@@ -9,8 +9,8 @@
 import com.android.cts.verifier.nfc.NfcDialogs;
 
 public class DefaultRouteEmulatorActivity extends BaseEmulatorActivity {
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu("A000000476416E64726F6964484345"),
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu("A000000476416E64726F6964484345", true),
     };
     public static final String[] APDU_RESPONSE_SEQUENCE = {
         "148100009000"
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualNonPaymentEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualNonPaymentEmulatorActivity.java
index 27b063c..0a9362a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualNonPaymentEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualNonPaymentEmulatorActivity.java
@@ -31,7 +31,7 @@
     public static Intent buildReaderIntent(Context context) {
         Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
         // Combine command/response APDU arrays
-        String[] commandSequences = new String[TransportService2.APDU_COMMAND_SEQUENCE.length +
+        CommandApdu[] commandSequences = new CommandApdu[TransportService2.APDU_COMMAND_SEQUENCE.length +
                                                AccessService.APDU_COMMAND_SEQUENCE.length];
         System.arraycopy(TransportService2.APDU_COMMAND_SEQUENCE, 0, commandSequences, 0,
                 TransportService2.APDU_COMMAND_SEQUENCE.length);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualNonPaymentPrefixEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualNonPaymentPrefixEmulatorActivity.java
new file mode 100644
index 0000000..c02faca
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualNonPaymentPrefixEmulatorActivity.java
@@ -0,0 +1,73 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.NfcDialogs;
+
+import java.util.ArrayList;
+
+public class DualNonPaymentPrefixEmulatorActivity extends BaseEmulatorActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_text);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setupServices(this, PrefixTransportService1.COMPONENT, PrefixAccessService.COMPONENT);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    void onServicesSetup(boolean result) {
+        // Do dynamic AID registration
+        ArrayList<String> service1_aids = new ArrayList<String>();
+        service1_aids.add(HceUtils.TRANSPORT_PREFIX_AID + "*");
+        ArrayList<String> service2_aids = new ArrayList<String>();
+        service2_aids.add(HceUtils.ACCESS_PREFIX_AID + "*");
+        mCardEmulation.registerAidsForService(PrefixTransportService1.COMPONENT, CardEmulation.CATEGORY_OTHER, service1_aids);
+        mCardEmulation.registerAidsForService(PrefixAccessService.COMPONENT, CardEmulation.CATEGORY_OTHER, service2_aids);
+        NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_other_prefix_aids_help)).show();
+    }
+
+    public static Intent buildReaderIntent(Context context) {
+        Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
+        // Combine command/response APDU arrays
+        CommandApdu[] commandSequences = new CommandApdu[PrefixTransportService1.APDU_COMMAND_SEQUENCE.length +
+                PrefixAccessService.APDU_COMMAND_SEQUENCE.length];
+        System.arraycopy(PrefixTransportService1.APDU_COMMAND_SEQUENCE, 0, commandSequences, 0,
+                PrefixTransportService1.APDU_COMMAND_SEQUENCE.length);
+        System.arraycopy(PrefixAccessService.APDU_COMMAND_SEQUENCE, 0, commandSequences,
+                PrefixTransportService1.APDU_COMMAND_SEQUENCE.length,
+                PrefixAccessService.APDU_COMMAND_SEQUENCE.length);
+
+        String[] responseSequences = new String[PrefixTransportService1.APDU_RESPOND_SEQUENCE.length +
+                PrefixAccessService.APDU_RESPOND_SEQUENCE.length];
+        System.arraycopy(PrefixTransportService1.APDU_RESPOND_SEQUENCE, 0, responseSequences, 0,
+                PrefixTransportService1.APDU_RESPOND_SEQUENCE.length);
+        System.arraycopy(PrefixAccessService.APDU_RESPOND_SEQUENCE, 0, responseSequences,
+                PrefixTransportService1.APDU_RESPOND_SEQUENCE.length,
+                PrefixAccessService.APDU_RESPOND_SEQUENCE.length);
+
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS, commandSequences);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES, responseSequences);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_LABEL,
+                context.getString(R.string.nfc_hce_other_prefix_aids_reader));
+        return readerIntent;
+    }
+
+    @Override
+    void onApduSequenceComplete(ComponentName component, long duration) {
+        if (component.equals(PrefixAccessService.COMPONENT)) {
+            getPassButton().setEnabled(true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualPaymentEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualPaymentEmulatorActivity.java
index 125045f..2e72e09 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualPaymentEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DualPaymentEmulatorActivity.java
@@ -1,11 +1,8 @@
 package com.android.cts.verifier.nfc.hce;
 
 import android.annotation.TargetApi;
-import android.app.AlertDialog;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.nfc.cardemulation.CardEmulation;
 import android.os.Bundle;
@@ -14,7 +11,7 @@
 import com.android.cts.verifier.nfc.NfcDialogs;
 
 @TargetApi(19)
-public class DualPaymentEmulatorActivity extends BaseEmulatorActivity implements OnClickListener {
+public class DualPaymentEmulatorActivity extends BaseEmulatorActivity {
     final static int STATE_IDLE = 0;
     final static int STATE_SERVICE1_SETTING_UP = 1;
     final static int STATE_SERVICE2_SETTING_UP = 2;
@@ -46,43 +43,28 @@
             return;
         }
         // Verify HCE service 2 is the default
-        if (!mCardEmulation.isDefaultServiceForCategory(
-                PaymentService2.COMPONENT, CardEmulation.CATEGORY_PAYMENT)) {
+        if (makePaymentDefault(PaymentService2.COMPONENT, R.string.nfc_hce_change_preinstalled_wallet)) {
             mState = STATE_MAKING_SERVICE2_DEFAULT;
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setTitle("Note");
-            builder.setMessage(R.string.nfc_hce_change_preinstalled_wallet);
-            builder.setPositiveButton("OK", this);
-            builder.show();
         } else {
+            // Already default
             NfcDialogs.createHceTapReaderDialog(this,null).show();
         }
     }
 
     @Override
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+        if (success) {
+            NfcDialogs.createHceTapReaderDialog(this, null).show();
+        }
+    }
+
+    @Override
     protected void onPause() {
         super.onPause();
         if (mReceiverRegistered) {
             unregisterReceiver(mReceiver);
         }
     }
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-        if (!mCardEmulation.isDefaultServiceForCategory(
-                PaymentService2.COMPONENT, CardEmulation.CATEGORY_PAYMENT)) {
-            // Popup dialog-box, fail test
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setTitle("Test failed.");
-            builder.setMessage("PaymentService2 is not the default service according " +
-                    "to CardEmulation.getDefaultServiceForCategory(), verify the make " +
-                    "default implementation is correct.");
-            builder.setPositiveButton("OK", null);
-            builder.show();
-        } else {
-            NfcDialogs.createHceTapReaderDialog(this, null).show();
-        }
-    }
     public static Intent buildReaderIntent(Context context) {
         Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
         readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS,
@@ -100,12 +82,4 @@
             getPassButton().setEnabled(true);
         }
     }
-
-    @Override
-    public void onClick(DialogInterface dialog, int which) {
-        Intent changeDefault = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
-        changeDefault.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_PAYMENT);
-        changeDefault.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, PaymentService2.COMPONENT);
-        startActivityForResult(changeDefault, 0);
-    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DynamicAidEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DynamicAidEmulatorActivity.java
new file mode 100644
index 0000000..ae8d50c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/DynamicAidEmulatorActivity.java
@@ -0,0 +1,73 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.NfcDialogs;
+
+import java.util.ArrayList;
+
+public class DynamicAidEmulatorActivity extends BaseEmulatorActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+       super.onCreate(savedInstanceState);
+       setContentView(R.layout.pass_fail_text);
+       setPassFailButtonClickListeners();
+       getPassButton().setEnabled(false);
+       setupServices(this, PaymentServiceDynamicAids.COMPONENT);
+    }
+
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+
+    @Override
+    void onServicesSetup(boolean result) {
+        ArrayList<String> paymentAids = new ArrayList<String>();
+        paymentAids.add(HceUtils.PPSE_AID);
+        paymentAids.add(HceUtils.VISA_AID);
+        // Register a different set of AIDs for the foreground
+        mCardEmulation.registerAidsForService(PaymentServiceDynamicAids.COMPONENT,
+                CardEmulation.CATEGORY_PAYMENT, paymentAids);
+        // Now make sure it's default
+        if (makePaymentDefault(PaymentServiceDynamicAids.COMPONENT,
+                R.string.nfc_hce_change_preinstalled_wallet)) {
+            // Wait for callback
+        } else {
+	        NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_payment_dynamic_aids_help)).show();
+        }
+    }
+
+    @Override
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+        if (success) {
+	        NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_payment_dynamic_aids_help)).show();
+        }
+    }
+
+    @Override
+    void onApduSequenceComplete(ComponentName component, long duration) {
+        if (component.equals(PaymentServiceDynamicAids.COMPONENT)) {
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    public static Intent buildReaderIntent(Context context) {
+        Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS,
+                PaymentServiceDynamicAids.APDU_COMMAND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES,
+                PaymentServiceDynamicAids.APDU_RESPOND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_LABEL,
+                context.getString(R.string.nfc_hce_payment_dynamic_aids_reader));
+        return readerIntent;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ForegroundNonPaymentEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ForegroundNonPaymentEmulatorActivity.java
new file mode 100644
index 0000000..e8bf5f1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ForegroundNonPaymentEmulatorActivity.java
@@ -0,0 +1,58 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.NfcDialogs;
+
+public class ForegroundNonPaymentEmulatorActivity extends BaseEmulatorActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_text);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        setupServices(this, TransportService1.COMPONENT, TransportService2.COMPONENT);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mCardEmulation.unsetPreferredService(this);
+    }
+
+    @Override
+    void onServicesSetup(boolean result) {
+        // Tell NFC service we prefer TransportService2
+        mCardEmulation.setPreferredService(this, TransportService2.COMPONENT);
+        NfcDialogs.createHceTapReaderDialog(this,
+                getString(R.string.nfc_hce_foreground_non_payment_help)).show();
+    }
+
+    public static Intent buildReaderIntent(Context context) {
+        Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS,
+                TransportService2.APDU_COMMAND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES,
+                TransportService2.APDU_RESPOND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_LABEL,
+                context.getString(R.string.nfc_hce_foreground_non_payment_reader));
+        return readerIntent;
+    }
+
+    @Override
+    void onApduSequenceComplete(ComponentName component, long duration) {
+        if (component.equals(TransportService2.COMPONENT)) {
+            getPassButton().setEnabled(true);
+        }
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ForegroundPaymentEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ForegroundPaymentEmulatorActivity.java
new file mode 100644
index 0000000..27cb061
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ForegroundPaymentEmulatorActivity.java
@@ -0,0 +1,75 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.NfcDialogs;
+
+@TargetApi(19)
+public class ForegroundPaymentEmulatorActivity extends BaseEmulatorActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_text);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (!mCardEmulation.categoryAllowsForegroundPreference(CardEmulation.CATEGORY_PAYMENT)) {
+            // Launch tap&pay settings
+            NfcDialogs.createChangeForegroundDialog(this).show();
+        } else {
+            setupServices(this, PaymentService2.COMPONENT, PaymentService1.COMPONENT);
+        }
+    }
+
+    @Override
+    void onServicesSetup(boolean result) {
+        if (!makePaymentDefault(PaymentService1.COMPONENT,
+                R.string.nfc_hce_change_preinstalled_wallet)) {
+            mCardEmulation.setPreferredService(this, PaymentService2.COMPONENT);
+            NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_foreground_payment_help)).show();
+        } // else, wait for callback
+    }
+
+    @Override
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+        if (success) {
+            NfcDialogs.createHceTapReaderDialog(this, null).show();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mCardEmulation.unsetPreferredService(this);
+    }
+
+    public static Intent buildReaderIntent(Context context) {
+        Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS,
+                PaymentService2.APDU_COMMAND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES,
+                PaymentService2.APDU_RESPOND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_LABEL,
+                context.getString(R.string.nfc_hce_foreground_payment_reader));
+        return readerIntent;
+    }
+
+    @Override
+    void onApduSequenceComplete(ComponentName component, long duration) {
+        if (component.equals(PaymentService2.COMPONENT)) {
+            getPassButton().setEnabled(true);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java
index e85d387..87fa3d1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceEmulatorTestActivity.java
@@ -23,6 +23,9 @@
 
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.nfc.NfcAdapter;
+import android.nfc.cardemulation.CardEmulation;
+import android.os.Build;
 import android.os.Bundle;
 
 /** Activity that lists all the NFC HCE emulator tests. */
@@ -37,6 +40,8 @@
 
         ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
 
+        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
+        CardEmulation cardEmulation = CardEmulation.getInstance(nfcAdapter);
         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
             adapter.add(TestListItem.newCategory(this, R.string.nfc_hce_emulator_tests));
 
@@ -62,6 +67,9 @@
                     ChangeDefaultEmulatorActivity.class.getName(),
                     new Intent(this, ChangeDefaultEmulatorActivity.class), null));
 
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_foreground_payment_emulator,
+                    ForegroundPaymentEmulatorActivity.class.getName(),
+                    new Intent(this, ForegroundPaymentEmulatorActivity.class), null));
 
             adapter.add(TestListItem.newTest(this, R.string.nfc_hce_single_non_payment_emulator,
                     SingleNonPaymentEmulatorActivity.class.getName(),
@@ -75,6 +83,10 @@
                     ConflictingNonPaymentEmulatorActivity.class.getName(),
                     new Intent(this, ConflictingNonPaymentEmulatorActivity.class), null));
 
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_foreground_non_payment_emulator,
+                    ForegroundNonPaymentEmulatorActivity.class.getName(),
+                    new Intent(this, ForegroundNonPaymentEmulatorActivity.class), null));
+
             adapter.add(TestListItem.newTest(this, R.string.nfc_hce_throughput_emulator,
                     ThroughputEmulatorActivity.class.getName(),
                     new Intent(this, ThroughputEmulatorActivity.class), null));
@@ -91,6 +103,29 @@
                     OnAndOffHostEmulatorActivity.class.getName(),
                     new Intent(this, OnAndOffHostEmulatorActivity.class), null));
 
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                adapter.add(TestListItem.newTest(this, R.string.nfc_hce_payment_dynamic_aids_emulator,
+                        DynamicAidEmulatorActivity.class.getName(),
+                        new Intent(this, DynamicAidEmulatorActivity.class), null));
+
+                if (cardEmulation.supportsAidPrefixRegistration()) {
+                    adapter.add(TestListItem.newTest(this, R.string.nfc_hce_payment_prefix_aids_emulator,
+                            PrefixPaymentEmulatorActivity.class.getName(),
+                            new Intent(this, PrefixPaymentEmulatorActivity.class), null));
+
+                    adapter.add(TestListItem.newTest(this, R.string.nfc_hce_payment_prefix_aids_emulator_2,
+                            PrefixPaymentEmulator2Activity.class.getName(),
+                            new Intent(this, PrefixPaymentEmulator2Activity.class), null));
+
+                    adapter.add(TestListItem.newTest(this, R.string.nfc_hce_other_prefix_aids_emulator,
+                            DualNonPaymentPrefixEmulatorActivity.class.getName(),
+                            new Intent(this, DualNonPaymentPrefixEmulatorActivity.class), null));
+
+                    adapter.add(TestListItem.newTest(this, R.string.nfc_hce_other_conflicting_prefix_aids_emulator,
+                            ConflictingNonPaymentPrefixEmulatorActivity.class.getName(),
+                            new Intent(this, ConflictingNonPaymentPrefixEmulatorActivity.class), null));
+                }
+            }
         }
 
         setTestListAdapter(adapter);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java
index 704cc89..f628fb7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceReaderTestActivity.java
@@ -61,6 +61,10 @@
                     SimpleReaderActivity.class.getName(),
                     ChangeDefaultEmulatorActivity.buildReaderIntent(this), null));
 
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_foreground_payment_reader,
+                    SimpleReaderActivity.class.getName(),
+                    ForegroundPaymentEmulatorActivity.buildReaderIntent(this), null));
+
             adapter.add(TestListItem.newTest(this, R.string.nfc_hce_single_non_payment_reader,
                     SimpleReaderActivity.class.getName(),
                     SingleNonPaymentEmulatorActivity.buildReaderIntent(this), null));
@@ -73,6 +77,10 @@
                     SimpleReaderActivity.class.getName(),
                     ConflictingNonPaymentEmulatorActivity.buildReaderIntent(this), null));
 
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_foreground_non_payment_reader,
+                    SimpleReaderActivity.class.getName(),
+                    ForegroundNonPaymentEmulatorActivity.buildReaderIntent(this), null));
+
             adapter.add(TestListItem.newTest(this, R.string.nfc_hce_throughput_reader,
                     SimpleReaderActivity.class.getName(),
                     ThroughputEmulatorActivity.buildReaderIntent(this), null));
@@ -88,6 +96,26 @@
             adapter.add(TestListItem.newTest(this, R.string.nfc_hce_on_and_offhost_service_reader,
                     SimpleReaderActivity.class.getName(),
                     OnAndOffHostEmulatorActivity.buildReaderIntent(this), null));
+
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_payment_dynamic_aids_reader,
+                    SimpleReaderActivity.class.getName(),
+                    DynamicAidEmulatorActivity.buildReaderIntent(this), null));
+
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_payment_prefix_aids_reader,
+                    SimpleReaderActivity.class.getName(),
+                    PrefixPaymentEmulatorActivity.buildReaderIntent(this), null));
+
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_payment_prefix_aids_reader_2,
+                    SimpleReaderActivity.class.getName(),
+                    PrefixPaymentEmulator2Activity.buildReaderIntent(this), null));
+
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_other_prefix_aids_reader,
+                    SimpleReaderActivity.class.getName(),
+                    DualNonPaymentPrefixEmulatorActivity.buildReaderIntent(this), null));
+
+            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_other_conflicting_prefix_aids_reader,
+                    SimpleReaderActivity.class.getName(),
+                    ConflictingNonPaymentPrefixEmulatorActivity.buildReaderIntent(this), null));
         }
 
         setTestListAdapter(adapter);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceService.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceService.java
index 20b34df..e9cd121 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceService.java
@@ -18,13 +18,13 @@
     final static int STATE_FAILED = 2;
 
     // Variables below only used on main thread
-    String[] mCommandApdus = null;
+    CommandApdu[] mCommandApdus = null;
     String[] mResponseApdus = null;
     int mApduIndex = 0;
     int mState = STATE_IDLE;
     long mStartTime;
 
-    public void initialize(String[] commandApdus, String[] responseApdus) {
+    public void initialize(CommandApdu[] commandApdus, String[] responseApdus) {
        mCommandApdus = commandApdus;
        mResponseApdus = responseApdus;
     }
@@ -62,12 +62,27 @@
             mStartTime = System.currentTimeMillis();
         }
 
+
+        if (mApduIndex >= mCommandApdus.length) {
+	        // Skip all APDUs which aren't supposed to reach us
+            return null;
+        }
+
+        do {
+            if (!mCommandApdus[mApduIndex].isReachable()) {
+                mApduIndex++;
+            } else {
+                break;
+            }
+        } while (mApduIndex < mCommandApdus.length);
+
         if (mApduIndex >= mCommandApdus.length) {
             Log.d(TAG, "Ignoring command APDU; protocol complete.");
             // Ignore new APDUs after completion
             return null;
         } else {
-            if (!Arrays.equals(HceUtils.hexStringToBytes(mCommandApdus[mApduIndex]), arg0)) {
+
+            if (!Arrays.equals(HceUtils.hexStringToBytes(mCommandApdus[mApduIndex].getApdu()), arg0)) {
                 Log.d(TAG, "Unexpected command APDU: " + HceUtils.getHexBytes("", arg0));
                 onApduSequenceError();
                 return null;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceUtils.java
index 3bab53b..c67169a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/HceUtils.java
@@ -14,10 +14,14 @@
 
     public static final String PPSE_AID = "325041592E5359532E4444463031";
     public static final String MC_AID = "A0000000041010";
+    public static final String VISA_AID = "A0000000030000";
 
     public static final String TRANSPORT_AID = "F001020304";
     public static final String ACCESS_AID = "F005060708";
 
+    public static final String TRANSPORT_PREFIX_AID = "F001020304";
+    public static final String ACCESS_PREFIX_AID = "F005060708";
+
     public static void enableComponent(PackageManager pm, ComponentName component) {
         pm.setComponentEnabledSetting(
                 component,
@@ -58,11 +62,15 @@
         return data;
     }
 
-    public static final String buildSelectApdu(String aid) {
+    public static final CommandApdu buildCommandApdu(String apdu, boolean reachable) {
+        return new CommandApdu(apdu, reachable);
+    }
+
+    public static final CommandApdu buildSelectApdu(String aid, boolean reachable) {
         StringBuilder sb = new StringBuilder();
         sb.append("00A40400");
         sb.append(String.format("%02X", aid.length() / 2));
         sb.append(aid);
-        return sb.toString();
+        return new CommandApdu(sb.toString(), reachable);
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OffHostService.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OffHostService.java
index c087c99..d8cdf19 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OffHostService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OffHostService.java
@@ -7,11 +7,11 @@
             new ComponentName("com.android.cts.verifier",
                     OffHostService.class.getName());
 
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu("A000000151000000"),
-        "80CA9F7F00",
-        HceUtils.buildSelectApdu("A000000003000000"),
-        "80CA9F7F00"
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu("A000000151000000", true),
+        HceUtils.buildCommandApdu("80CA9F7F00", true),
+        HceUtils.buildSelectApdu("A000000003000000", true),
+        HceUtils.buildCommandApdu("80CA9F7F00", true)
     };
 
     public static final String[] APDU_RESPOND_SEQUENCE = {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OnAndOffHostEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OnAndOffHostEmulatorActivity.java
index 3d5190f..d599959 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OnAndOffHostEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/OnAndOffHostEmulatorActivity.java
@@ -6,8 +6,8 @@
 import android.content.Intent;
 import android.os.Bundle;
 
-import com.android.cts.verifier.R;
 import com.android.cts.verifier.nfc.NfcDialogs;
+import com.android.cts.verifier.R;
 
 @TargetApi(19)
 public class OnAndOffHostEmulatorActivity extends BaseEmulatorActivity {
@@ -32,7 +32,7 @@
 
     public static Intent buildReaderIntent(Context context) {
         // Combine command/response APDU arrays
-        String[] commandSequences = new String[OffHostService.APDU_COMMAND_SEQUENCE.length +
+        CommandApdu[] commandSequences = new CommandApdu[OffHostService.APDU_COMMAND_SEQUENCE.length +
                                                AccessService.APDU_COMMAND_SEQUENCE.length];
         System.arraycopy(OffHostService.APDU_COMMAND_SEQUENCE, 0, commandSequences, 0,
                 OffHostService.APDU_COMMAND_SEQUENCE.length);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService1.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService1.java
index f6119eb..80df0cb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService1.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService1.java
@@ -9,10 +9,10 @@
             new ComponentName("com.android.cts.verifier",
             PaymentService1.class.getName());
 
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu(HceUtils.PPSE_AID),
-        HceUtils.buildSelectApdu(HceUtils.MC_AID),
-        "80CA01F000"
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.PPSE_AID, true),
+        HceUtils.buildSelectApdu(HceUtils.MC_AID, true),
+        HceUtils.buildCommandApdu("80CA01F000", true)
     };
 
     public static final String[] APDU_RESPOND_SEQUENCE = {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService2.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService2.java
index 23664b9..f2c4835 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService2.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentService2.java
@@ -7,9 +7,9 @@
             new ComponentName("com.android.cts.verifier",
             PaymentService2.class.getName());
 
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu(HceUtils.PPSE_AID),
-        HceUtils.buildSelectApdu(HceUtils.MC_AID)
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.PPSE_AID, true),
+        HceUtils.buildSelectApdu(HceUtils.MC_AID, true)
     };
 
     public static final String[] APDU_RESPOND_SEQUENCE = {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentServiceDynamicAids.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentServiceDynamicAids.java
new file mode 100644
index 0000000..047a667
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PaymentServiceDynamicAids.java
@@ -0,0 +1,32 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+
+public class PaymentServiceDynamicAids extends HceService {
+    static final String TAG = "PaymentService1";
+
+    static final ComponentName COMPONENT =
+            new ComponentName("com.android.cts.verifier",
+            PaymentServiceDynamicAids.class.getName());
+
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.PPSE_AID, true),
+        HceUtils.buildSelectApdu(HceUtils.VISA_AID, true),
+        HceUtils.buildCommandApdu("80CA01F000", true)
+    };
+
+    public static final String[] APDU_RESPOND_SEQUENCE = {
+        "FFFF9000",
+        "FF0F9000",
+        "FFDFFFAACB9000"
+    };
+
+    public PaymentServiceDynamicAids() {
+        initialize(APDU_COMMAND_SEQUENCE, APDU_RESPOND_SEQUENCE);
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixAccessService.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixAccessService.java
new file mode 100644
index 0000000..8cecb56
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixAccessService.java
@@ -0,0 +1,34 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+
+public class PrefixAccessService extends HceService {
+    static final String TAG = "PrefixAccessService";
+
+    static final ComponentName COMPONENT =
+            new ComponentName("com.android.cts.verifier",
+            PrefixAccessService.class.getName());
+
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.ACCESS_PREFIX_AID + "FFFF", true),
+        HceUtils.buildSelectApdu(HceUtils.ACCESS_PREFIX_AID + "FFAA", true),
+        HceUtils.buildSelectApdu(HceUtils.ACCESS_PREFIX_AID + "FFAABBCCDDEEFF", true),
+        HceUtils.buildCommandApdu("80CA010000010203", true)
+    };
+
+    public static final String[] APDU_RESPOND_SEQUENCE = {
+        "FAFE9000",
+        "FAFE25929000",
+        "FAFEAABB25929000",
+        "FAFEFFAACC25929000"
+    };
+
+    public PrefixAccessService() {
+        initialize(APDU_COMMAND_SEQUENCE, APDU_RESPOND_SEQUENCE);
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentEmulator2Activity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentEmulator2Activity.java
new file mode 100644
index 0000000..5ed6fe9
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentEmulator2Activity.java
@@ -0,0 +1,84 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.NfcDialogs;
+
+@TargetApi(19)
+public class PrefixPaymentEmulator2Activity extends BaseEmulatorActivity {
+    final static int STATE_IDLE = 0;
+    final static int STATE_SERVICE1_SETTING_UP = 1;
+    final static int STATE_SERVICE2_SETTING_UP = 2;
+    final static int STATE_MAKING_SERVICE2_DEFAULT = 3;
+
+    boolean mReceiverRegistered = false;
+    int mState = STATE_IDLE;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_text);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        mState = STATE_SERVICE2_SETTING_UP;
+        setupServices(this, PrefixPaymentService2.COMPONENT);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    void onServicesSetup(boolean result) {
+        if (mState == STATE_SERVICE2_SETTING_UP) {
+            mState = STATE_SERVICE1_SETTING_UP;
+            setupServices(this, PrefixPaymentService1.COMPONENT, PrefixPaymentService2.COMPONENT);
+            return;
+        }
+        // Verify HCE service 2 is the default
+        if (makePaymentDefault(PrefixPaymentService2.COMPONENT, R.string.nfc_hce_change_preinstalled_wallet)) {
+            mState = STATE_MAKING_SERVICE2_DEFAULT;
+        } else {
+            // Already default
+            NfcDialogs.createHceTapReaderDialog(this,getString(R.string.nfc_hce_payment_prefix_aids_help)).show();
+        }
+    }
+
+    @Override
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+        if (success) {
+            NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_payment_prefix_aids_help)).show();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (mReceiverRegistered) {
+            unregisterReceiver(mReceiver);
+        }
+    }
+    public static Intent buildReaderIntent(Context context) {
+        Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS,
+                PrefixPaymentService2.APDU_COMMAND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES,
+                PrefixPaymentService2.APDU_RESPOND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_LABEL,
+                context.getString(R.string.nfc_hce_payment_prefix_aids_reader_2));
+        return readerIntent;
+    }
+
+    @Override
+    void onApduSequenceComplete(ComponentName component, long duration) {
+        if (component.equals(PrefixPaymentService2.COMPONENT)) {
+            getPassButton().setEnabled(true);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentEmulatorActivity.java
new file mode 100644
index 0000000..d3a4189
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentEmulatorActivity.java
@@ -0,0 +1,84 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.NfcDialogs;
+
+@TargetApi(19)
+public class PrefixPaymentEmulatorActivity extends BaseEmulatorActivity {
+    final static int STATE_IDLE = 0;
+    final static int STATE_SERVICE1_SETTING_UP = 1;
+    final static int STATE_SERVICE2_SETTING_UP = 2;
+    final static int STATE_MAKING_SERVICE1_DEFAULT = 3;
+
+    boolean mReceiverRegistered = false;
+    int mState = STATE_IDLE;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_text);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        mState = STATE_SERVICE1_SETTING_UP;
+        setupServices(this, PrefixPaymentService1.COMPONENT);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    void onServicesSetup(boolean result) {
+        if (mState == STATE_SERVICE1_SETTING_UP) {
+            mState = STATE_SERVICE2_SETTING_UP;
+            setupServices(this, PrefixPaymentService1.COMPONENT, PrefixPaymentService2.COMPONENT);
+            return;
+        }
+        // Verify HCE service 1 is the default
+        if (makePaymentDefault(PrefixPaymentService1.COMPONENT, R.string.nfc_hce_change_preinstalled_wallet)) {
+            mState = STATE_MAKING_SERVICE1_DEFAULT;
+        } else {
+            // Already default
+            NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_payment_prefix_aids_help)).show();
+        }
+    }
+
+    @Override
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+        if (success) {
+            NfcDialogs.createHceTapReaderDialog(this, getString(R.string.nfc_hce_payment_prefix_aids_help)).show();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (mReceiverRegistered) {
+            unregisterReceiver(mReceiver);
+        }
+    }
+    public static Intent buildReaderIntent(Context context) {
+        Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS,
+                PrefixPaymentService1.APDU_COMMAND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES,
+                PrefixPaymentService1.APDU_RESPOND_SEQUENCE);
+        readerIntent.putExtra(SimpleReaderActivity.EXTRA_LABEL,
+                context.getString(R.string.nfc_hce_payment_prefix_aids_reader));
+        return readerIntent;
+    }
+
+    @Override
+    void onApduSequenceComplete(ComponentName component, long duration) {
+        if (component.equals(PrefixPaymentService1.COMPONENT)) {
+            getPassButton().setEnabled(true);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentService1.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentService1.java
new file mode 100644
index 0000000..be6acc2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentService1.java
@@ -0,0 +1,32 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+
+public class PrefixPaymentService1 extends HceService {
+    static final String TAG = "PrefixPaymentService1";
+
+    static final ComponentName COMPONENT =
+            new ComponentName("com.android.cts.verifier",
+            PrefixPaymentService1.class.getName());
+
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.PPSE_AID, true),
+        HceUtils.buildSelectApdu(HceUtils.MC_AID, true),
+        HceUtils.buildCommandApdu("80CA01F000", true)
+    };
+
+    public static final String[] APDU_RESPOND_SEQUENCE = {
+        "F1239000",
+        "F4569000",
+        "F789FFAABB9000"
+    };
+
+    public PrefixPaymentService1() {
+        initialize(APDU_COMMAND_SEQUENCE, APDU_RESPOND_SEQUENCE);
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentService2.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentService2.java
new file mode 100644
index 0000000..9642025
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixPaymentService2.java
@@ -0,0 +1,36 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+
+public class PrefixPaymentService2 extends HceService {
+    static final String TAG = "PrefixPaymentService2";
+
+    static final ComponentName COMPONENT =
+            new ComponentName("com.android.cts.verifier",
+            PrefixPaymentService2.class.getName());
+
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.PPSE_AID, true),
+        HceUtils.buildSelectApdu(HceUtils.MC_AID, true),
+        HceUtils.buildCommandApdu("80CA02F000", true),
+        HceUtils.buildSelectApdu("F0000000FFFFFFFFFFFFFFFFFFFFFFFF", true),
+        HceUtils.buildSelectApdu("F000000000", true)
+    };
+
+    public static final String[] APDU_RESPOND_SEQUENCE = {
+        "FAAA9000",
+        "FBBB9000",
+        "F789FFCCDD9000",
+        "FFBAFEBECA",
+        "F0BABEFECA"
+    };
+
+    public PrefixPaymentService2() {
+        initialize(APDU_COMMAND_SEQUENCE, APDU_RESPOND_SEQUENCE);
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixTransportService1.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixTransportService1.java
new file mode 100644
index 0000000..5521440
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixTransportService1.java
@@ -0,0 +1,34 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+
+public class PrefixTransportService1 extends HceService {
+    static final String TAG = "PrefixTransportService1";
+
+    static final ComponentName COMPONENT =
+            new ComponentName("com.android.cts.verifier",
+            PrefixTransportService1.class.getName());
+
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_PREFIX_AID + "FFFF", true),
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_PREFIX_AID + "FFAA", true),
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_PREFIX_AID + "FFAABBCCDDEEFF", true),
+        HceUtils.buildCommandApdu("80CA01FFAA", true)
+    };
+
+    public static final String[] APDU_RESPOND_SEQUENCE = {
+        "25929000",
+        "FFEF25929000",
+        "FFDFFFAABB25929000",
+        "FFDFFFAACC25929000"
+    };
+
+    public PrefixTransportService1() {
+        initialize(APDU_COMMAND_SEQUENCE, APDU_RESPOND_SEQUENCE);
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixTransportService2.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixTransportService2.java
new file mode 100644
index 0000000..2235446
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/PrefixTransportService2.java
@@ -0,0 +1,34 @@
+package com.android.cts.verifier.nfc.hce;
+
+import android.content.ComponentName;
+
+public class PrefixTransportService2 extends HceService {
+    static final String TAG = "PrefixTransportService2";
+
+    static final ComponentName COMPONENT =
+            new ComponentName("com.android.cts.verifier",
+            PrefixTransportService2.class.getName());
+
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_PREFIX_AID + "FFFF", true),
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_PREFIX_AID + "FFAA", true),
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_PREFIX_AID + "FFAABBCCDDEEFF", true),
+        HceUtils.buildCommandApdu("80CA01FFBB", true)
+    };
+
+    public static final String[] APDU_RESPOND_SEQUENCE = {
+        "36039000",
+        "FFBB25929000",
+        "FFDFFFBBBB25929000",
+        "FFDFFFBBCC25929000"
+    };
+
+    public PrefixTransportService2() {
+        initialize(APDU_COMMAND_SEQUENCE, APDU_RESPOND_SEQUENCE);
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SimpleReaderActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SimpleReaderActivity.java
index 6c15811..638bc6f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SimpleReaderActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SimpleReaderActivity.java
@@ -9,6 +9,7 @@
 import android.nfc.tech.IsoDep;
 import android.nfc.Tag;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.util.Log;
 import android.view.View;
 import android.widget.AdapterView;
@@ -34,7 +35,7 @@
     public static final String EXTRA_LABEL = "label";
 
     NfcAdapter mAdapter;
-    String[] mApdus;
+    CommandApdu[] mApdus;
     String[] mResponses;
 
     TextView mTextView;
@@ -76,7 +77,15 @@
         mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A |
                 NfcAdapter.FLAG_READER_NFC_BARCODE | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
         Intent intent = getIntent();
-        mApdus = intent.getStringArrayExtra(EXTRA_APDUS);
+        Parcelable[] apdus = intent.getParcelableArrayExtra(EXTRA_APDUS);
+        if (apdus != null) {
+	        mApdus = new CommandApdu[apdus.length];
+	        for (int i = 0; i < apdus.length; i++) {
+	            mApdus[i] = (CommandApdu) apdus[i];
+	        }
+        } else {
+            mApdus = null;
+        }
         mResponses = intent.getStringArrayExtra(EXTRA_RESPONSES);
     }
 
@@ -95,11 +104,11 @@
             int count = 0;
             boolean success = true;
             long startTime = System.currentTimeMillis();
-            for (String apdu: mApdus) {
+            for (CommandApdu apdu: mApdus) {
                 sb.append("Request APDU:\n");
-                sb.append(apdu + "\n\n");
+                sb.append(apdu.getApdu() + "\n\n");
                 long apduStartTime = System.currentTimeMillis();
-                byte[] response = isoDep.transceive(HceUtils.hexStringToBytes(apdu));
+                byte[] response = isoDep.transceive(HceUtils.hexStringToBytes(apdu.getApdu()));
                 long apduEndTime = System.currentTimeMillis();
                 sb.append("Response APDU (in " + Long.toString(apduEndTime - apduStartTime) +
                         " ms):\n");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SinglePaymentEmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SinglePaymentEmulatorActivity.java
index 13b2fe8..0f1fba0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SinglePaymentEmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/SinglePaymentEmulatorActivity.java
@@ -1,19 +1,15 @@
 package com.android.cts.verifier.nfc.hce;
 
 import android.annotation.TargetApi;
-import android.app.AlertDialog;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
-import android.nfc.cardemulation.CardEmulation;
 import android.os.Bundle;
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.nfc.NfcDialogs;
 
 @TargetApi(19)
-public class SinglePaymentEmulatorActivity extends BaseEmulatorActivity implements OnClickListener {
+public class SinglePaymentEmulatorActivity extends BaseEmulatorActivity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -31,18 +27,21 @@
     @Override
     void onServicesSetup(boolean result) {
         // Verify HCE service 1 is the default
-        if (!mCardEmulation.isDefaultServiceForCategory(
-                PaymentService1.COMPONENT, CardEmulation.CATEGORY_PAYMENT)) {
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setTitle("Note");
-            builder.setMessage(R.string.nfc_hce_change_preinstalled_wallet);
-            builder.setPositiveButton("OK", this);
-            builder.show();
+        if (makePaymentDefault(PaymentService1.COMPONENT,
+                R.string.nfc_hce_change_preinstalled_wallet)) {
+            // Wait for callback
         } else {
 	        NfcDialogs.createHceTapReaderDialog(this, null).show();
         }
     }
 
+    @Override
+    void onPaymentDefaultResult(ComponentName component, boolean success) {
+        if (success) {
+	        NfcDialogs.createHceTapReaderDialog(this, null).show();
+        }
+    }
+
     public static Intent buildReaderIntent(Context context) {
         Intent readerIntent = new Intent(context, SimpleReaderActivity.class);
         readerIntent.putExtra(SimpleReaderActivity.EXTRA_APDUS,
@@ -60,30 +59,4 @@
             getPassButton().setEnabled(true);
         }
     }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-        if (!mCardEmulation.isDefaultServiceForCategory(
-                PaymentService1.COMPONENT, CardEmulation.CATEGORY_PAYMENT)) {
-            // Popup dialog-box, fail test
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setTitle("Test failed.");
-            builder.setMessage("PaymentService1 is not the default service according " +
-                    "to CardEmulation.getDefaultServiceForCategory(), verify the make " +
-                    "default implementation is correct.");
-            builder.setPositiveButton("OK", null);
-            builder.show();
-        } else {
-            NfcDialogs.createHceTapReaderDialog(this, null).show();
-        }
-    }
-
-    @Override
-    public void onClick(DialogInterface dialog, int which) {
-        Intent changeDefault = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
-        changeDefault.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_PAYMENT);
-        changeDefault.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, PaymentService1.COMPONENT);
-        startActivityForResult(changeDefault, 0);
-    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ThroughputService.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ThroughputService.java
index 8f826ff..b74f0b7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ThroughputService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/ThroughputService.java
@@ -9,23 +9,23 @@
             new ComponentName("com.android.cts.verifier",
             ThroughputService.class.getName());
 
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu("F0010203040607FF"),
-        "80CA010000",
-        "80CA010100",
-        "80CA010200",
-        "80CA010300",
-        "80CA010400",
-        "80CA010500",
-        "80CA010600",
-        "80CA010700",
-        "80CA010800",
-        "80CA010900",
-        "80CA010A00",
-        "80CA010B00",
-        "80CA010C00",
-        "80CA010D00",
-        "80CA010E00",
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu("F0010203040607FF", true),
+        HceUtils.buildCommandApdu("80CA010100", true),
+        HceUtils.buildCommandApdu("80CA010200", true),
+        HceUtils.buildCommandApdu("80CA010300", true),
+        HceUtils.buildCommandApdu("80CA010400", true),
+        HceUtils.buildCommandApdu("80CA010500", true),
+        HceUtils.buildCommandApdu("80CA010600", true),
+        HceUtils.buildCommandApdu("80CA010700", true),
+        HceUtils.buildCommandApdu("80CA010800", true),
+        HceUtils.buildCommandApdu("80CA010900", true),
+        HceUtils.buildCommandApdu("80CA010A00", true),
+        HceUtils.buildCommandApdu("80CA010B00", true),
+        HceUtils.buildCommandApdu("80CA010C00", true),
+        HceUtils.buildCommandApdu("80CA010D00", true),
+        HceUtils.buildCommandApdu("80CA010E00", true),
+        HceUtils.buildCommandApdu("80CA010F00", true),
     };
 
     public static final String[] APDU_RESPOND_SEQUENCE = {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService1.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService1.java
index c751e76..c8d8460 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService1.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService1.java
@@ -7,9 +7,9 @@
             new ComponentName("com.android.cts.verifier",
             TransportService1.class.getName());
 
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_AID),
-        "80CA01E000"
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_AID, true),
+        HceUtils.buildCommandApdu("80CA01E000", true)
     };
 
     public static final String[] APDU_RESPOND_SEQUENCE = {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService2.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService2.java
index 0815b9c..322a076 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService2.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/hce/TransportService2.java
@@ -7,9 +7,9 @@
             new ComponentName("com.android.cts.verifier",
             TransportService2.class.getName());
 
-    public static final String[] APDU_COMMAND_SEQUENCE = {
-        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_AID),
-        "80CA01E100"
+    public static final CommandApdu[] APDU_COMMAND_SEQUENCE = {
+        HceUtils.buildSelectApdu(HceUtils.TRANSPORT_AID, true),
+        HceUtils.buildCommandApdu("80CA01E100", true)
     };
 
     public static final String[] APDU_RESPOND_SEQUENCE = {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nls/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/nls/MockListener.java
deleted file mode 100644
index 0b74fa3..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nls/MockListener.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.verifier.nls;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class MockListener extends NotificationListenerService {
-    static final String TAG = "MockListener";
-
-    static final String SERVICE_CHECK = "android.service.notification.cts.SERVICE_CHECK";
-    static final String SERVICE_POSTED = "android.service.notification.cts.SERVICE_POSTED";
-    static final String SERVICE_PAYLOADS = "android.service.notification.cts.SERVICE_PAYLOADS";
-    static final String SERVICE_REMOVED = "android.service.notification.cts.SERVICE_REMOVED";
-    static final String SERVICE_RESET = "android.service.notification.cts.SERVICE_RESET";
-    static final String SERVICE_CLEAR_ONE = "android.service.notification.cts.SERVICE_CLEAR_ONE";
-    static final String SERVICE_CLEAR_ALL = "android.service.notification.cts.SERVICE_CLEAR_ALL";
-
-    static final String EXTRA_PAYLOAD = "TAGS";
-    static final String EXTRA_TAG = "TAG";
-    static final String EXTRA_CODE = "CODE";
-
-    static final int RESULT_TIMEOUT = Activity.RESULT_FIRST_USER;
-    static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
-
-    public static final String JSON_FLAGS = "flag";
-    public static final String JSON_ICON = "icon";
-    public static final String JSON_ID = "id";
-    public static final String JSON_PACKAGE = "pkg";
-    public static final String JSON_WHEN = "when";
-    public static final String JSON_TAG = "tag";
-
-    private ArrayList<String> mPosted = new ArrayList<String>();
-    private ArrayList<String> mPayloads = new ArrayList<String>();
-    private ArrayList<String> mRemoved = new ArrayList<String>();
-    private BroadcastReceiver mReceiver;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        Log.d(TAG, "created");
-
-        mPosted = new ArrayList<String>();
-        mRemoved = new ArrayList<String>();
-
-        mReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (SERVICE_CHECK.equals(action)) {
-                    Log.d(TAG, "SERVICE_CHECK");
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_POSTED.equals(action)) {
-                    Log.d(TAG, "SERVICE_POSTED");
-                    Bundle bundle = new Bundle();
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_PAYLOADS.equals(action)) {
-                    Log.d(TAG, "SERVICE_PAYLOADS");
-                    Bundle bundle = new Bundle();
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, mPayloads);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_REMOVED.equals(action)) {
-                    Log.d(TAG, "SERVICE_REMOVED");
-                    Bundle bundle = new Bundle();
-                    bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
-                    setResultExtras(bundle);
-                    setResultCode(Activity.RESULT_OK);
-                } else if (SERVICE_CLEAR_ONE.equals(action)) {
-                    Log.d(TAG, "SERVICE_CLEAR_ONE");
-                    MockListener.this.cancelNotification(
-                            context.getApplicationInfo().packageName,
-                            intent.getStringExtra(EXTRA_TAG),
-                            intent.getIntExtra(EXTRA_CODE, 0));
-                } else if (SERVICE_CLEAR_ALL.equals(action)) {
-                    Log.d(TAG, "SERVICE_CLEAR_ALL");
-                    MockListener.this.cancelAllNotifications();
-                } else if (SERVICE_RESET.equals(action)) {
-                    Log.d(TAG, "SERVICE_RESET");
-                    resetData();
-                } else {
-                    Log.w(TAG, "unknown action");
-                    setResultCode(Activity.RESULT_CANCELED);
-                }
-            }
-        };
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(SERVICE_CHECK);
-        filter.addAction(SERVICE_POSTED);
-        filter.addAction(SERVICE_PAYLOADS);
-        filter.addAction(SERVICE_REMOVED);
-        filter.addAction(SERVICE_CLEAR_ONE);
-        filter.addAction(SERVICE_CLEAR_ALL);
-        filter.addAction(SERVICE_RESET);
-        registerReceiver(mReceiver, filter);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        unregisterReceiver(mReceiver);
-        mReceiver = null;
-        Log.d(TAG, "destroyed");
-    }
-
-    public void resetData() {
-        mPosted.clear();
-        mPayloads.clear();
-        mRemoved.clear();
-    }
-
-    @Override
-    public void onNotificationPosted(StatusBarNotification sbn) {
-        Log.d(TAG, "posted: " + sbn.getTag());
-        mPosted.add(sbn.getTag());
-        JSONObject payload = new JSONObject();
-        try {
-            payload.put(JSON_TAG, sbn.getTag());
-            payload.put(JSON_ID, sbn.getId());
-            payload.put(JSON_PACKAGE, sbn.getPackageName());
-            payload.put(JSON_WHEN, sbn.getNotification().when);
-            payload.put(JSON_ICON, sbn.getNotification().icon);
-            payload.put(JSON_FLAGS, sbn.getNotification().flags);
-            mPayloads.add(payload.toString());
-        } catch (JSONException e) {
-            Log.e(TAG, "failed to pack up notification payload", e);
-        }
-    }
-
-    @Override
-    public void onNotificationRemoved(StatusBarNotification sbn) {
-        Log.d(TAG, "removed: " + sbn.getTag());
-        mRemoved.add(sbn.getTag());
-    }
-
-    public static void resetListenerData(Context context) {
-        sendCommand(context, SERVICE_RESET, null, 0);
-    }
-
-    public static void probeListenerStatus(Context context, IntegerResultCatcher catcher) {
-        requestIntegerResult(context, SERVICE_CHECK, catcher);
-    }
-
-    public static void probeListenerPosted(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_POSTED, catcher);
-    }
-
-    public static void probeListenerPayloads(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_PAYLOADS, catcher);
-    }
-
-    public static void probeListenerRemoved(Context context, StringListResultCatcher catcher) {
-        requestStringListResult(context, SERVICE_REMOVED, catcher);
-    }
-
-    public static void clearOne(Context context, String tag, int code) {
-        sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
-    }
-
-    public static void clearAll(Context context) {
-        sendCommand(context, SERVICE_CLEAR_ALL, null, 0);
-    }
-
-    private static void sendCommand(Context context, String action, String tag, int code) {
-        Intent broadcast = new Intent(action);
-        if (tag != null) {
-            broadcast.putExtra(EXTRA_TAG, tag);
-            broadcast.putExtra(EXTRA_CODE, code);
-        }
-        context.sendBroadcast(broadcast);
-    }
-
-    public abstract static class IntegerResultCatcher extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            accept(Integer.valueOf(getResultCode()));
-        }
-
-        abstract public void accept(int result);
-    }
-
-    private static void requestIntegerResult(Context context, String action,
-            IntegerResultCatcher catcher) {
-        Intent broadcast = new Intent(action);
-        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
-    }
-
-    public abstract static class StringListResultCatcher extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            accept(getResultExtras(true).getStringArrayList(EXTRA_PAYLOAD));
-        }
-
-        abstract public void accept(List<String> result);
-    }
-
-    private static void requestStringListResult(Context context, String action,
-            StringListResultCatcher catcher) {
-        Intent broadcast = new Intent(action);
-        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nls/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nls/NotificationListenerVerifierActivity.java
deleted file mode 100644
index 842c024..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nls/NotificationListenerVerifierActivity.java
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.nls;
-
-import static com.android.cts.verifier.nls.MockListener.JSON_FLAGS;
-import static com.android.cts.verifier.nls.MockListener.JSON_ICON;
-import static com.android.cts.verifier.nls.MockListener.JSON_ID;
-import static com.android.cts.verifier.nls.MockListener.JSON_PACKAGE;
-import static com.android.cts.verifier.nls.MockListener.JSON_TAG;
-import static com.android.cts.verifier.nls.MockListener.JSON_WHEN;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.provider.Settings.Secure;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-import com.android.cts.verifier.nfc.TagVerifierActivity;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class NotificationListenerVerifierActivity extends PassFailButtons.Activity
-implements Runnable {
-    static final String TAG = TagVerifierActivity.class.getSimpleName();
-    private static final String STATE = "state";
-    private static final String LISTENER_PATH = "com.android.cts.verifier/" + 
-            "com.android.cts.verifier.nls.MockListener";
-    private static final int SETUP = 0;
-    private static final int PASS = 1;
-    private static final int FAIL = 2;
-    private static final int WAIT_FOR_USER = 3;
-    private static final int CLEARED = 4;
-    private static final int READY = 5;
-    private static final int RETRY = 6;
-    private static final int NOTIFICATION_ID = 1001;
-    private static LinkedBlockingQueue<String> sDeletedQueue = new LinkedBlockingQueue<String>();
-
-    private int mState;
-    private int[] mStatus;
-    private LayoutInflater mInflater;
-    private ViewGroup mItemList;
-    private PackageManager mPackageManager;
-    private String mTag1;
-    private String mTag2;
-    private String mTag3;
-    private NotificationManager mNm;
-    private Context mContext;
-    private Runnable mRunner;
-    private View mHandler;
-    private String mPackageString;
-    private int mIcon1;
-    private int mIcon2;
-    private int mIcon3;
-    private int mId1;
-    private int mId2;
-    private int mId3;
-    private long mWhen1;
-    private long mWhen2;
-    private long mWhen3;
-    private int mFlag1;
-    private int mFlag2;
-    private int mFlag3;
-
-    public static class DismissService extends Service {
-        @Override
-        public IBinder onBind(Intent intent) {
-            return null;
-        }
-
-        @Override
-        public void onStart(Intent intent, int startId) {
-            sDeletedQueue.offer(intent.getAction());
-        }
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        if (savedInstanceState != null) {
-            mState = savedInstanceState.getInt(STATE, 0);
-        }
-        mContext = this;
-        mRunner = this;
-        mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-        mPackageManager = getPackageManager();
-        mInflater = getLayoutInflater();
-        View view = mInflater.inflate(R.layout.nls_main, null);
-        mItemList = (ViewGroup) view.findViewById(R.id.nls_test_items);
-        mHandler = mItemList;
-        createTestItems();
-        mStatus = new int[mItemList.getChildCount()];
-        setContentView(view);
-
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.nls_test, R.string.nls_info, -1);
-
-        getPassButton().setEnabled(false);
-    }
-
-    @Override
-    protected void onSaveInstanceState (Bundle outState) {
-        outState.putInt(STATE, mState);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        next();
-    }
-
-    // Interface Utilities
-
-    private void createTestItems() {
-        createUserItem(R.string.nls_enable_service);
-        createAutoItem(R.string.nls_service_started);
-        createAutoItem(R.string.nls_note_received);
-        createAutoItem(R.string.nls_payload_intact);
-        createAutoItem(R.string.nls_clear_one);
-        createAutoItem(R.string.nls_clear_all);
-        createUserItem(R.string.nls_disable_service);
-        createAutoItem(R.string.nls_service_stopped);
-        createAutoItem(R.string.nls_note_missed);
-    }
-
-    private void setItemState(int index, boolean passed) {
-        ViewGroup item = (ViewGroup) mItemList.getChildAt(index);
-        ImageView status = (ImageView) item.findViewById(R.id.nls_status);
-        status.setImageResource(passed ? R.drawable.fs_good : R.drawable.fs_error);
-        View button = item.findViewById(R.id.nls_launch_settings);
-        button.setClickable(false);
-        button.setEnabled(false);
-        status.invalidate();
-    }
-
-    private void markItemWaiting(int index) {
-        ViewGroup item = (ViewGroup) mItemList.getChildAt(index);
-        ImageView status = (ImageView) item.findViewById(R.id.nls_status);
-        status.setImageResource(R.drawable.fs_warning);
-        status.invalidate();
-    }
-
-    private View createUserItem(int stringId) {
-        View item = mInflater.inflate(R.layout.nls_item, mItemList, false);
-        TextView instructions = (TextView) item.findViewById(R.id.nls_instructions);
-        instructions.setText(stringId);
-        mItemList.addView(item);
-        return item;
-    }
-
-    private View createAutoItem(int stringId) {
-        View item = mInflater.inflate(R.layout.nls_item, mItemList, false);
-        TextView instructions = (TextView) item.findViewById(R.id.nls_instructions);
-        instructions.setText(stringId);
-        View button = item.findViewById(R.id.nls_launch_settings);
-        button.setVisibility(View.GONE);
-        mItemList.addView(item);
-        return item;
-    }
-
-    // Test management
-
-    public void run() {
-        while (mState < mStatus.length && mStatus[mState] != WAIT_FOR_USER) {
-            if (mStatus[mState] == PASS) {
-                setItemState(mState, true);
-                mState++;
-            } else if (mStatus[mState] == FAIL) {
-                setItemState(mState, false);
-                return;
-            } else {
-                break;
-            }
-        }
-
-        if (mState < mStatus.length && mStatus[mState] == WAIT_FOR_USER) {
-            markItemWaiting(mState);
-        }
-
-        switch (mState) {
-            case 0:
-                testIsEnabled(0);
-                break;
-            case 1:
-                testIsStarted(1);
-                break;
-            case 2:
-                testNotificationRecieved(2);
-                break;
-            case 3:
-                testDataIntact(3);
-                break;
-            case 4:
-                testDismissOne(4);
-                break;
-            case 5:
-                testDismissAll(5);
-                break;
-            case 6:
-                testIsDisabled(6);
-                break;
-            case 7:
-                testIsStopped(7);
-                break;
-            case 8:
-                testNotificationNotRecieved(8);
-                break;
-            case 9:
-                getPassButton().setEnabled(true);
-                mNm.cancelAll();
-                break;
-        }
-    }
-
-    public void launchSettings(View button) {
-        startActivity(
-                new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
-    }
-
-    private PendingIntent makeIntent(int code, String tag) {
-        Intent intent = new Intent(tag);
-        intent.setComponent(new ComponentName(mContext, DismissService.class));
-        PendingIntent pi = PendingIntent.getService(mContext, code, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-        return pi;
-    }
-
-    @SuppressLint("NewApi")
-    private void sendNotificaitons() {
-        mTag1 = UUID.randomUUID().toString();
-        mTag2 = UUID.randomUUID().toString();
-        mTag3 = UUID.randomUUID().toString();
-
-        mNm.cancelAll();
-
-        mWhen1 = System.currentTimeMillis() + 1;
-        mWhen2 = System.currentTimeMillis() + 2;
-        mWhen3 = System.currentTimeMillis() + 3;
-
-        mIcon1 = R.drawable.fs_good;
-        mIcon2 = R.drawable.fs_error;
-        mIcon3 = R.drawable.fs_warning;
-
-        mId1 = NOTIFICATION_ID + 1;
-        mId2 = NOTIFICATION_ID + 2;
-        mId3 = NOTIFICATION_ID + 3;
-
-        mPackageString = "com.android.cts.verifier";
-
-        Notification n1 = new Notification.Builder(mContext)
-        .setContentTitle("ClearTest 1")
-        .setContentText(mTag1.toString())
-        .setPriority(Notification.PRIORITY_LOW)
-        .setSmallIcon(mIcon1)
-        .setWhen(mWhen1)
-        .setDeleteIntent(makeIntent(1, mTag1))
-        .setOnlyAlertOnce(true)
-        .build();
-        mNm.notify(mTag1, mId1, n1);
-        mFlag1 = Notification.FLAG_ONLY_ALERT_ONCE;
-
-        Notification n2 = new Notification.Builder(mContext)
-        .setContentTitle("ClearTest 2")
-        .setContentText(mTag2.toString())
-        .setPriority(Notification.PRIORITY_HIGH)
-        .setSmallIcon(mIcon2)
-        .setWhen(mWhen2)
-        .setDeleteIntent(makeIntent(2, mTag2))
-        .setAutoCancel(true)
-        .build();
-        mNm.notify(mTag2, mId2, n2);
-        mFlag2 = Notification.FLAG_AUTO_CANCEL;
-
-        Notification n3 = new Notification.Builder(mContext)
-        .setContentTitle("ClearTest 3")
-        .setContentText(mTag3.toString())
-        .setPriority(Notification.PRIORITY_LOW)
-        .setSmallIcon(mIcon3)
-        .setWhen(mWhen3)
-        .setDeleteIntent(makeIntent(3, mTag3))
-        .setAutoCancel(true)
-        .setOnlyAlertOnce(true)
-        .build();
-        mNm.notify(mTag3, mId3, n3);
-        mFlag3 = Notification.FLAG_ONLY_ALERT_ONCE | Notification.FLAG_AUTO_CANCEL;
-    }
-
-    /**
-     * Return to the state machine to progress through the tests.
-     */
-    private void next() {
-        mHandler.post(mRunner);
-    }
-
-    /**
-     * Wait for things to settle before returning to the state machine.
-     */
-    private void delay() {
-        mHandler.postDelayed(mRunner, 2000);
-    }
-
-    boolean checkEquals(long expected, long actual, String message) {
-        if (expected == actual) {
-            return true;
-        }
-        logWithStack(String.format(message, expected, actual));
-        return false;
-    }
-
-    boolean checkEquals(String expected, String actual, String message) {
-        if (expected.equals(actual)) {
-            return true;
-        }
-        logWithStack(String.format(message, expected, actual));
-        return false;
-    }
-
-    boolean checkFlagSet(int expected, int actual, String message) {
-        if ((expected & actual) != 0) {
-            return true;
-        }
-        logWithStack(String.format(message, expected, actual));
-        return false;
-    };
-
-    private void logWithStack(String message) {
-        Throwable stackTrace = new Throwable();
-        stackTrace.fillInStackTrace();
-        Log.e(TAG, message, stackTrace);
-    }
-
-    // Tests
-
-    private void testIsEnabled(int i) {
-        // no setup required
-        Intent settings = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
-        if (settings.resolveActivity(mPackageManager) == null) {
-            logWithStack("failed testIsEnabled: no settings activity");
-            mStatus[i] = FAIL;
-        } else {
-            // TODO: find out why Secure.ENABLED_NOTIFICATION_LISTENERS is hidden
-            String listeners = Secure.getString(getContentResolver(),
-                    "enabled_notification_listeners");
-            if (listeners != null && listeners.contains(LISTENER_PATH)) {
-                mStatus[i] = PASS;
-            } else {
-                mStatus[i] = WAIT_FOR_USER;
-            }
-        }
-        next();
-    }
-
-    private void testIsStarted(final int i) {
-        if (mStatus[i] == SETUP) {
-            mStatus[i] = READY;
-            // wait for the service to start
-            delay();
-        } else {
-            MockListener.probeListenerStatus(mContext,
-                    new MockListener.IntegerResultCatcher() {
-                @Override
-                public void accept(int result) {
-                    if (result == Activity.RESULT_OK) {
-                        mStatus[i] = PASS;
-                    } else {
-                        logWithStack("failed testIsStarted: " + result);
-                        mStatus[i] = FAIL;
-                    }
-                    next();
-                }
-            });
-        }
-    }
-
-    private void testNotificationRecieved(final int i) {
-        if (mStatus[i] == SETUP) {
-            MockListener.resetListenerData(this);
-            mStatus[i] = CLEARED;
-            // wait for intent to move through the system
-            delay();
-        } else if (mStatus[i] == CLEARED) {
-            sendNotificaitons();
-            mStatus[i] = READY;
-            // wait for notifications to move through the system
-            delay();
-        } else {
-            MockListener.probeListenerPosted(mContext,
-                    new MockListener.StringListResultCatcher() {
-                @Override
-                public void accept(List<String> result) {
-                    if (result.size() > 0 && result.contains(mTag1)) {
-                        mStatus[i] = PASS;
-                    } else {
-                        logWithStack("failed testNotificationRecieved");
-                        mStatus[i] = FAIL;
-                    }
-                    next();
-                }});
-        }
-    }
-
-    private void testDataIntact(final int i) {
-        // no setup required
-        MockListener.probeListenerPayloads(mContext,
-                new MockListener.StringListResultCatcher() {
-            @Override
-            public void accept(List<String> result) {
-                boolean pass = false;
-                Set<String> found = new HashSet<String>();
-                if (result.size() > 0) {
-                    pass = true;
-                    for(String payloadData : result) {
-                        try {
-                            JSONObject payload = new JSONObject(payloadData);
-                            pass &= checkEquals(mPackageString, payload.getString(JSON_PACKAGE),
-                                    "data integrity test fail: notificaiton package (%s, %s)");
-                            String tag = payload.getString(JSON_TAG);
-                            if (mTag1.equals(tag)) {
-                                found.add(mTag1);
-                                pass &= checkEquals(mIcon1, payload.getInt(JSON_ICON),
-                                        "data integrity test fail: notificaiton icon (%d, %d)");
-                                pass &= checkFlagSet(mFlag1, payload.getInt(JSON_FLAGS),
-                                        "data integrity test fail: notificaiton flags (%d, %d)");
-                                pass &= checkEquals(mId1, payload.getInt(JSON_ID),
-                                        "data integrity test fail: notificaiton ID (%d, %d)");
-                                pass &= checkEquals(mWhen1, payload.getLong(JSON_WHEN),
-                                        "data integrity test fail: notificaiton when (%d, %d)");
-                            } else if (mTag2.equals(tag)) {
-                                found.add(mTag2);
-                                pass &= checkEquals(mIcon2, payload.getInt(JSON_ICON),
-                                        "data integrity test fail: notificaiton icon (%d, %d)");
-                                pass &= checkFlagSet(mFlag2, payload.getInt(JSON_FLAGS),
-                                        "data integrity test fail: notificaiton flags (%d, %d)");
-                                pass &= checkEquals(mId2, payload.getInt(JSON_ID),
-                                        "data integrity test fail: notificaiton ID (%d, %d)");
-                                pass &= checkEquals(mWhen2, payload.getLong(JSON_WHEN),
-                                        "data integrity test fail: notificaiton when (%d, %d)");
-                            } else if (mTag3.equals(tag)) {
-                                found.add(mTag3);
-                                pass &= checkEquals(mIcon3, payload.getInt(JSON_ICON),
-                                        "data integrity test fail: notificaiton icon (%d, %d)");
-                                pass &= checkFlagSet(mFlag3, payload.getInt(JSON_FLAGS),
-                                        "data integrity test fail: notificaiton flags (%d, %d)");
-                                pass &= checkEquals(mId3, payload.getInt(JSON_ID),
-                                        "data integrity test fail: notificaiton ID (%d, %d)");
-                                pass &= checkEquals(mWhen3, payload.getLong(JSON_WHEN),
-                                        "data integrity test fail: notificaiton when (%d, %d)");
-                            } else {
-                                pass = false;
-                                logWithStack("failed on unexpected notification tag: " + tag);
-                            }
-                        } catch (JSONException e) {
-                            pass = false;
-                            Log.e(TAG, "failed to unpack data from mocklistener", e);
-                        }
-                    }
-                }
-                pass &= found.size() == 3;
-                mStatus[i] = pass ? PASS : FAIL;
-                next();
-            }});
-    }
-
-    private void testDismissOne(final int i) {
-        if (mStatus[i] == SETUP) {
-            MockListener.resetListenerData(this);
-            mStatus[i] = CLEARED;
-            // wait for intent to move through the system
-            delay();
-        } else if (mStatus[i] == CLEARED) {
-            MockListener.clearOne(mContext, mTag1, NOTIFICATION_ID + 1);
-            mStatus[i] = READY;
-            delay();
-        } else {
-            MockListener.probeListenerRemoved(mContext,
-                    new MockListener.StringListResultCatcher() {
-                @Override
-                public void accept(List<String> result) {
-                    if (result.size() > 0 && result.contains(mTag1)) {
-                        mStatus[i] = PASS;
-                        next();
-                    } else {
-                        if (mStatus[i] == RETRY) {
-                            logWithStack("failed testDismissOne");
-                            mStatus[i] = FAIL;
-                            next();
-                        } else {
-                            logWithStack("failed testDismissOne, once: retrying");
-                            mStatus[i] = RETRY;
-                            delay();
-                        }
-                    }
-                }});
-        }
-    }
-
-    private void testDismissAll(final int i) {
-        if (mStatus[i] == SETUP) {
-            MockListener.resetListenerData(this);
-            mStatus[i] = CLEARED;
-            // wait for intent to move through the system
-            delay();
-        } else if (mStatus[i] == CLEARED) {
-            MockListener.clearAll(mContext);
-            mStatus[i] = READY;
-            delay();
-        } else {
-            MockListener.probeListenerRemoved(mContext,
-                    new MockListener.StringListResultCatcher() {
-                @Override
-                public void accept(List<String> result) {
-                    if (result.size() == 2 && result.contains(mTag2) && result.contains(mTag3)) {
-                        mStatus[i] = PASS;
-                        next();
-                    } else {
-                        if (mStatus[i] == RETRY) {
-                            logWithStack("failed testDismissAll");
-                            mStatus[i] = FAIL;
-                            next();
-                        } else {
-                            logWithStack("failed testDismissAll, once: retrying");
-                            mStatus[i] = RETRY;
-                            delay();
-                        }
-                    }
-                }
-            });
-        }
-    }
-
-    private void testIsDisabled(int i) {
-        // no setup required
-        // TODO: find out why Secure.ENABLED_NOTIFICATION_LISTENERS is hidden
-        String listeners = Secure.getString(getContentResolver(),
-                "enabled_notification_listeners");
-        if (listeners == null || !listeners.contains(LISTENER_PATH)) {
-            mStatus[i] = PASS;
-            next();
-        } else {
-            mStatus[i] = WAIT_FOR_USER;
-            delay();
-        }
-    }
-
-    private void testIsStopped(final int i) {
-        if (mStatus[i] == SETUP) {
-            mStatus[i] = READY;
-            // wait for the service to start
-            delay();
-        } else {
-            MockListener.probeListenerStatus(mContext,
-                    new MockListener.IntegerResultCatcher() {
-                @Override
-                public void accept(int result) {
-                    if (result == Activity.RESULT_OK) {
-                        logWithStack("failed testIsStopped");
-                        mStatus[i] = FAIL;
-                    } else {
-                        mStatus[i] = PASS;
-                    }
-                    next();
-                }
-            });
-        }
-    }
-
-    private void testNotificationNotRecieved(final int i) {
-        if (mStatus[i] == SETUP) {
-            MockListener.resetListenerData(this);
-            mStatus[i] = CLEARED;
-            // wait for intent to move through the system
-            delay();
-        } else if (mStatus[i] == CLEARED) {
-            // setup for testNotificationRecieved
-            sendNotificaitons();
-            mStatus[i] = READY;
-            delay();
-        } else {
-            MockListener.probeListenerPosted(mContext,
-                    new MockListener.StringListResultCatcher() {
-                @Override
-                public void accept(List<String> result) {
-                    if (result == null || result.size() == 0) {
-                        mStatus[i] = PASS;
-                    } else {
-                        logWithStack("failed testNotificationNotRecieved");
-                        mStatus[i] = FAIL;
-                    }
-                    next();
-                }});
-        }
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
new file mode 100644
index 0000000..b4863fa
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.verifier.notifications;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class MockListener extends NotificationListenerService {
+    static final String TAG = "MockListener";
+
+    static final String SERVICE_BASE = "android.service.notification.cts.";
+    static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
+    static final String SERVICE_POSTED = SERVICE_BASE + "SERVICE_POSTED";
+    static final String SERVICE_PAYLOADS = SERVICE_BASE + "SERVICE_PAYLOADS";
+    static final String SERVICE_REMOVED = SERVICE_BASE + "SERVICE_REMOVED";
+    static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
+    static final String SERVICE_CLEAR_ONE = SERVICE_BASE + "SERVICE_CLEAR_ONE";
+    static final String SERVICE_CLEAR_ALL = SERVICE_BASE + "SERVICE_CLEAR_ALL";
+    public static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
+    public static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+
+    static final String EXTRA_PAYLOAD = "PAYLOAD";
+    static final String EXTRA_INT = "INT";
+    static final String EXTRA_TAG = "TAG";
+    static final String EXTRA_CODE = "CODE";
+
+    static final int RESULT_TIMEOUT = Activity.RESULT_FIRST_USER;
+    static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
+
+    public static final String JSON_FLAGS = "flag";
+    public static final String JSON_ICON = "icon";
+    public static final String JSON_ID = "id";
+    public static final String JSON_PACKAGE = "pkg";
+    public static final String JSON_WHEN = "when";
+    public static final String JSON_TAG = "tag";
+    public static final String JSON_RANK = "rank";
+    public static final String JSON_AMBIENT = "ambient";
+    public static final String JSON_MATCHES_ZEN_FILTER = "matches_zen_filter";
+
+    private ArrayList<String> mPosted = new ArrayList<String>();
+    private ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
+    private ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
+    private ArrayList<String> mRemoved = new ArrayList<String>();
+    private ArrayList<String> mOrder = new ArrayList<>();
+    private Set<String> mTestPackages = new HashSet<>();
+    private BroadcastReceiver mReceiver;
+    private int mDND = -1;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "created");
+
+        mTestPackages.add("com.android.cts.verifier");
+
+        mPosted = new ArrayList<String>();
+        mRemoved = new ArrayList<String>();
+
+        mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (SERVICE_CHECK.equals(action)) {
+                    Log.d(TAG, "SERVICE_CHECK");
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_POSTED.equals(action)) {
+                    Log.d(TAG, "SERVICE_POSTED");
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_DND.equals(action)) {
+                    Log.d(TAG, "SERVICE_DND");
+                    Bundle bundle = new Bundle();
+                    bundle.putInt(EXTRA_INT, mDND);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_ORDER.equals(action)) {
+                    Log.d(TAG, "SERVICE_ORDER");
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_PAYLOADS.equals(action)) {
+                    Log.d(TAG, "SERVICE_PAYLOADS");
+                    Bundle bundle = new Bundle();
+                    ArrayList<String> payloadData = new ArrayList<>(mNotifications.size());
+                    for (JSONObject payload: mNotifications.values()) {
+                        payloadData.add(payload.toString());
+                    }
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, payloadData);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_REMOVED.equals(action)) {
+                    Log.d(TAG, "SERVICE_REMOVED");
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_CLEAR_ONE.equals(action)) {
+                    Log.d(TAG, "SERVICE_CLEAR_ONE");
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    if (key != null) {
+                        MockListener.this.cancelNotification(key);
+                    } else {
+                        Log.w(TAG, "Notification does not exist: " + tag);
+                    }
+                } else if (SERVICE_CLEAR_ALL.equals(action)) {
+                    Log.d(TAG, "SERVICE_CLEAR_ALL");
+                    MockListener.this.cancelAllNotifications();
+                } else if (SERVICE_RESET.equals(action)) {
+                    Log.d(TAG, "SERVICE_RESET");
+                    resetData();
+                } else {
+                    Log.w(TAG, "unknown action");
+                    setResultCode(Activity.RESULT_CANCELED);
+                }
+            }
+        };
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(SERVICE_CHECK);
+        filter.addAction(SERVICE_DND);
+        filter.addAction(SERVICE_POSTED);
+        filter.addAction(SERVICE_ORDER);
+        filter.addAction(SERVICE_PAYLOADS);
+        filter.addAction(SERVICE_REMOVED);
+        filter.addAction(SERVICE_CLEAR_ONE);
+        filter.addAction(SERVICE_CLEAR_ALL);
+        filter.addAction(SERVICE_RESET);
+        registerReceiver(mReceiver, filter);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+        mReceiver = null;
+        Log.d(TAG, "destroyed");
+    }
+
+    @Override
+    public void onListenerConnected() {
+        super.onListenerConnected();
+        mDND = getCurrentInterruptionFilter();
+        Log.d(TAG, "initial value of CurrentInterruptionFilter is " + mDND);
+    }
+
+    @Override
+    public void onInterruptionFilterChanged(int interruptionFilter) {
+        super.onInterruptionFilterChanged(interruptionFilter);
+        mDND = interruptionFilter;
+        Log.d(TAG, "value of CurrentInterruptionFilter changed to " + mDND);
+    }
+
+    public void resetData() {
+        mPosted.clear();
+        mNotifications.clear();
+        mRemoved.clear();
+        mOrder.clear();
+    }
+
+    @Override
+    public void onNotificationRankingUpdate(RankingMap rankingMap) {
+        String[] orderedKeys = rankingMap.getOrderedKeys();
+        mOrder.clear();
+        Ranking rank = new Ranking();
+        for( int i = 0; i < orderedKeys.length; i++) {
+            String key = orderedKeys[i];
+            mOrder.add(key);
+            rankingMap.getRanking(key, rank);
+            JSONObject note = mNotifications.get(key);
+            if (note != null) {
+                try {
+                    note.put(JSON_RANK, rank.getRank());
+                    note.put(JSON_AMBIENT, rank.isAmbient());
+                    note.put(JSON_MATCHES_ZEN_FILTER, rank.matchesInterruptionFilter());
+                } catch (JSONException e) {
+                    Log.e(TAG, "failed to pack up notification payload", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+        if (!mTestPackages.contains(sbn.getPackageName())) { return; }
+        Log.d(TAG, "posted: " + sbn.getTag());
+        mPosted.add(sbn.getTag());
+        JSONObject notification = new JSONObject();
+        try {
+            notification.put(JSON_TAG, sbn.getTag());
+            notification.put(JSON_ID, sbn.getId());
+            notification.put(JSON_PACKAGE, sbn.getPackageName());
+            notification.put(JSON_WHEN, sbn.getNotification().when);
+            notification.put(JSON_ICON, sbn.getNotification().icon);
+            notification.put(JSON_FLAGS, sbn.getNotification().flags);
+            mNotifications.put(sbn.getKey(), notification);
+            mNotificationKeys.put(sbn.getTag(), sbn.getKey());
+        } catch (JSONException e) {
+            Log.e(TAG, "failed to pack up notification payload", e);
+        }
+        onNotificationRankingUpdate(rankingMap);
+    }
+
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+        Log.d(TAG, "removed: " + sbn.getTag());
+        mRemoved.add(sbn.getTag());
+        mNotifications.remove(sbn.getKey());
+        onNotificationRankingUpdate(rankingMap);
+        mNotificationKeys.remove(sbn.getTag());
+    }
+
+    public static void resetListenerData(Context context) {
+        sendCommand(context, SERVICE_RESET, null, 0);
+    }
+
+    public static void probeListenerStatus(Context context, StatusCatcher catcher) {
+        requestStatus(context, SERVICE_CHECK, catcher);
+    }
+
+    public static void probeFilter(Context context, IntegerResultCatcher catcher) {
+        requestIntegerResult(context, SERVICE_DND, catcher);
+    }
+
+    public static void probeListenerPosted(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_POSTED, catcher);
+    }
+
+    public static void probeListenerOrder(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_ORDER, catcher);
+    }
+
+    public static void probeListenerPayloads(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_PAYLOADS, catcher);
+    }
+
+    public static void probeListenerRemoved(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_REMOVED, catcher);
+    }
+
+    public static void clearOne(Context context, String tag, int code) {
+        sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
+    }
+
+    public static void clearAll(Context context) {
+        sendCommand(context, SERVICE_CLEAR_ALL, null, 0);
+    }
+
+    private static void sendCommand(Context context, String action, String tag, int code) {
+        Intent broadcast = new Intent(action);
+        if (tag != null) {
+            broadcast.putExtra(EXTRA_TAG, tag);
+            broadcast.putExtra(EXTRA_CODE, code);
+        }
+        context.sendBroadcast(broadcast);
+    }
+
+    public abstract static class StatusCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(Integer.valueOf(getResultCode()));
+        }
+
+        abstract public void accept(int result);
+    }
+
+    private static void requestStatus(Context context, String action,
+            StatusCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+
+    public abstract static class IntegerResultCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(getResultExtras(true).getInt(EXTRA_INT, -1));
+        }
+
+        abstract public void accept(int result);
+    }
+
+    private static void requestIntegerResult(Context context, String action,
+            IntegerResultCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+
+    public abstract static class StringListResultCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(getResultExtras(true).getStringArrayList(EXTRA_PAYLOAD));
+        }
+
+        abstract public void accept(List<String> result);
+    }
+
+    private static void requestStringListResult(Context context, String action,
+            StringListResultCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAttentionManagementVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAttentionManagementVerifierActivity.java
new file mode 100644
index 0000000..b4e348f
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAttentionManagementVerifierActivity.java
@@ -0,0 +1,883 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.notifications;
+
+import static com.android.cts.verifier.notifications.MockListener.JSON_AMBIENT;
+import static com.android.cts.verifier.notifications.MockListener.JSON_MATCHES_ZEN_FILTER;
+import static com.android.cts.verifier.notifications.MockListener.JSON_TAG;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.content.ContentProviderOperation;
+import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.Settings.Secure;
+import android.service.notification.NotificationListenerService;
+import android.util.Log;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.nfc.TagVerifierActivity;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class NotificationAttentionManagementVerifierActivity
+        extends NotificationListenerVerifierActivity {
+    private static final String TAG = TagVerifierActivity.class.getSimpleName();
+    private static final String ALICE = "Alice";
+    private static final String ALICE_PHONE = "+16175551212";
+    private static final String ALICE_EMAIL = "alice@_foo._bar";
+    private static final String BOB = "Bob";
+    private static final String BOB_PHONE = "+16505551212";;
+    private static final String BOB_EMAIL = "bob@_foo._bar";
+    private static final String CHARLIE = "Charlie";
+    private static final String CHARLIE_PHONE = "+13305551212";
+    private static final String CHARLIE_EMAIL = "charlie@_foo._bar";
+    private static final int MODE_NONE = 0;
+    private static final int MODE_URI = 1;
+    private static final int MODE_PHONE = 2;
+    private static final int MODE_EMAIL = 3;
+    private static final int DELAYED_SETUP = CLEARED;
+
+    private Uri mAliceUri;
+    private Uri mBobUri;
+    private Uri mCharlieUri;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState, R.layout.nls_main);
+        setInfoResources(R.string.attention_test, R.string.attention_info, -1);
+    }
+
+    // Test Setup
+
+    @Override
+    protected void createTestItems() {
+        createNlsSettingsItem(R.string.nls_enable_service);
+        createAutoItem(R.string.nls_service_started);
+        createAutoItem(R.string.attention_create_contacts);
+        createRetryItem(R.string.attention_filter_none);
+        createAutoItem(R.string.attention_all_are_filtered);
+        createRetryItem(R.string.attention_filter_all);
+        createAutoItem(R.string.attention_none_are_filtered);
+        createAutoItem(R.string.attention_default_order);
+        createAutoItem(R.string.attention_interruption_order);
+        createAutoItem(R.string.attention_priority_order);
+        createAutoItem(R.string.attention_ambient_bit);
+        createAutoItem(R.string.attention_lookup_order);
+        createAutoItem(R.string.attention_email_order);
+        createAutoItem(R.string.attention_phone_order);
+        createRetryItem(R.string.attention_filter_priority);
+        createAutoItem(R.string.attention_some_are_filtered);
+        createAutoItem(R.string.attention_delete_contacts);
+    }
+
+    // Test management
+
+    @Override
+    protected void updateStateMachine() {
+        switch (mState) {
+            case 0:
+                testIsEnabled(mState);
+                break;
+            case 1:
+                testIsStarted(mState);
+                break;
+            case 2:
+                testInsertContacts(mState);
+                break;
+            case 3:
+                testModeNone(mState);
+                break;
+            case 4:
+                testNoneInterceptsAll(mState);
+                break;
+            case 5:
+                testModeAll(mState);
+                break;
+            case 6:
+                testAllInterceptsNothing(mState);
+                break;
+            case 7:
+                testDefaultOrder(mState);
+                break;
+            case 8:
+                testInterruptionOrder(mState);
+                break;
+            case 9:
+                testPrioritytOrder(mState);
+                break;
+            case 10:
+                testAmbientBits(mState);
+                break;
+            case 11:
+                testLookupUriOrder(mState);
+                break;
+            case 12:
+                testEmailOrder(mState);
+                break;
+            case 13:
+                testPhoneOrder(mState);
+                break;
+            case 14:
+                testModePriority(mState);
+                break;
+            case 15:
+                testPriorityInterceptsSome(mState);
+                break;
+            case 16:
+                testDeleteContacts(mState);
+                break;
+            case 17:
+                getPassButton().setEnabled(true);
+                mNm.cancelAll();
+                break;
+        }
+    }
+
+    // usePriorities true: B, C, A
+    // usePriorities false:
+    //   MODE_NONE: C, B, A
+    //   otherwise: A, B ,C
+    private void sendNotifications(int annotationMode, boolean usePriorities, boolean noisy) {
+        // TODO(cwren) Fixes flakey tests due to bug 17644321. Remove this line when it is fixed.
+        int baseId = NOTIFICATION_ID + (noisy ? 3 : 0);
+
+        // C, B, A when sorted by time.  Times must be in the past.
+        long whenA = System.currentTimeMillis() - 4000000L;
+        long whenB = System.currentTimeMillis() - 2000000L;
+        long whenC = System.currentTimeMillis() - 1000000L;
+
+        // B, C, A when sorted by priorities
+        int priorityA = usePriorities ? Notification.PRIORITY_MIN : Notification.PRIORITY_DEFAULT;
+        int priorityB = usePriorities ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
+        int priorityC = usePriorities ? Notification.PRIORITY_LOW : Notification.PRIORITY_DEFAULT;
+
+        Notification.Builder alice = new Notification.Builder(mContext)
+                .setContentTitle(ALICE)
+                .setContentText(ALICE)
+                .setSmallIcon(R.drawable.fs_good)
+                .setPriority(priorityA)
+                .setCategory(Notification.CATEGORY_MESSAGE)
+                .setWhen(whenA);
+        alice.setDefaults(noisy ? Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE : 0);
+        addPerson(annotationMode, alice, mAliceUri, ALICE_PHONE, ALICE_EMAIL);
+        mNm.notify(ALICE, baseId + 1, alice.build());
+
+        Notification.Builder bob = new Notification.Builder(mContext)
+                .setContentTitle(BOB)
+                .setContentText(BOB)
+                .setSmallIcon(R.drawable.fs_warning)
+                .setPriority(priorityB)
+                .setCategory(Notification.CATEGORY_MESSAGE)
+                .setWhen(whenB);
+        addPerson(annotationMode, bob, mBobUri, BOB_PHONE, BOB_EMAIL);
+        mNm.notify(BOB, baseId + 2, bob.build());
+
+        Notification.Builder charlie = new Notification.Builder(mContext)
+                .setContentTitle(CHARLIE)
+                .setContentText(CHARLIE)
+                .setSmallIcon(R.drawable.fs_error)
+                .setPriority(priorityC)
+                .setCategory(Notification.CATEGORY_MESSAGE)
+                .setWhen(whenC);
+        addPerson(annotationMode, charlie, mCharlieUri, CHARLIE_PHONE, CHARLIE_EMAIL);
+        mNm.notify(CHARLIE, baseId + 3, charlie.build());
+    }
+
+    private void addPerson(int mode, Notification.Builder note,
+            Uri uri, String phone, String email) {
+        if (mode == MODE_URI && uri != null) {
+            note.addPerson(uri.toString());
+        } else if (mode == MODE_PHONE) {
+            note.addPerson(Uri.fromParts("tel", phone, null).toString());
+        } else if (mode == MODE_EMAIL) {
+            note.addPerson(Uri.fromParts("mailto", email, null).toString());
+        }
+    }
+
+    // Tests
+
+    private void testIsEnabled(int i) {
+        // no setup required
+        Intent settings = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
+        if (settings.resolveActivity(mPackageManager) == null) {
+            logWithStack("failed testIsEnabled: no settings activity");
+            mStatus[i] = FAIL;
+        } else {
+            // TODO: find out why Secure.ENABLED_NOTIFICATION_LISTENERS is hidden
+            String listeners = Secure.getString(getContentResolver(),
+                    "enabled_notification_listeners");
+            if (listeners != null && listeners.contains(LISTENER_PATH)) {
+                mStatus[i] = PASS;
+            } else {
+                mStatus[i] = WAIT_FOR_USER;
+            }
+        }
+        next();
+    }
+
+    private void testIsStarted(final int i) {
+        if (mStatus[i] == SETUP) {
+            mStatus[i] = READY;
+            // wait for the service to start
+            delay();
+        } else {
+            MockListener.probeListenerStatus(mContext,
+                    new MockListener.StatusCatcher() {
+                        @Override
+                        public void accept(int result) {
+                            if (result == Activit